Single header only C++ logging library. It is extremely light-weight, robust, fast performing, thread and type safe and consists of many built-in features. It provides ability to write logs in your own customized format. It also provide support for logging your classes, third-party libraries, STL and third-party containers etc.
برای انتقال دادهها از طریق WCF بین سیستمهای مختلف باید دادههای مورد نظر حتما سریالایز شوند که مثال هایی از این دست رو در همین سایت میتونید مطالعه کنید:
(^ ) و (^ ) و (^ )
با توجه به این که دادهها سریالایز میشوند، در نتیجه امکان انقال داده هایی که از نوع object هستند در WCF وجود ندارد. بلکه نوع داده باید صراحتا ذکر شود و این نوع باید قابیلت سریالایز شدن را دارا باشد.برای مثال شما نمیتونید متدی داشته باشید که پارامتر ورودی آن از نوع delegate باشد یا کلاسی باشد که صفت [Serializable] در بالای اون قرار نداشته باشد یا کلاسی باشد که صفت DataContract برای خود کلاس و صفت DataMember برای خاصیتهای اون تعریف نشده باشد. حالا سوال مهم این است اگر متدی داشته باشیم که پارامتر ورودی آن حتما باید از نوع delegate باشد چه باید کرد؟
برای تشریح بهتر مسئله یک مثال میزنم؟
سرویسی داریم برای اطلاعات کتاب ها. قصد داریم متدی بنوسیم که پارامتر
ورودی آن از نوع Lambda Expression است تا Query مورد نظر کاربر از سمت
کلاینت به سمت سرور دریافت کند و خروجی مورد نظر را با توجه به Query ورودی
به کلاینت برگشت دهد.( متدی متداول در اکثر پروژه ها). به صورت زیر عمل میکنیم.
*ابتدا یک Blank Solution ایجاد کنید.
*یک ClassLibrary به نام Model ایجاد کنید و کلاسی به نام Book در آن بسازید .(همانطور که میبینید کلاس مورد نظر سریالایز شده است):
[DataContract] public class Book { [DataMember] public int Code { get; set; } [DataMember] public string Title { get; set; } }
یک Contract برای ارتباط بین سرور و کلاینت میسازیم:
using System; using System.Collections.Generic; using System.Linq.Expressions; using System.ServiceModel; namespace WcfLambdaExpression { [ServiceContract] public interface IBookService { [OperationContract] IEnumerable<Book> GetByExpression( Expression<Func<Book, bool>> expression ); } }
using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; namespace WcfLambdaExpression { public class BookService : IBookService { public BookService() { ListOfBook = new List<Book>(); } public List<Book> ListOfBook { get; private set; } public IEnumerable<Book> GetByExpression( Expression<Func<Book, bool>> expression ) { ListOfBook.AddRange( new Book[] { new Book(){Code = 1 , Title = "Book1"}, new Book(){Code = 2 , Title = "Book2"}, new Book(){Code = 3 , Title = "Book3"}, new Book(){Code = 4 , Title = "Book4"}, new Book(){Code = 5 , Title = "Book5"}, } ); return ListOfBook.AsQueryable().Where( expression ); } } }
به طور حتم با خطا روبرو خواهید شد. دلیل آن هم این است که امکان سریالایز کردن برای پارامتر ورودی expression میسر نیست.
خطای مربوطه به شکل زیر خواهد بود:
Type 'System.Linq.Expressions.Expression`1[System.Func`2[WcfLambdaExpression.Book,System.Boolean]]' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. If the type is a collection, consider marking it with the CollectionDataContractAttribute. See the Microsoft .NET Framework documentation for other supported types
روشهای زیادی برای بر طرف کردن این محدودیت وجود دارد. اما در این پست روشی رو که خودم از اون استفاده میکنم رو براتون شرح میدهم.
در این روش باید از XElement استفاده شود که در فضای نام System.Linq.Xml قرار دارد. یعنی آرگومان ورودی سمت کلاینت باید به فرمت Xml سریالایز شود و سمت سرور دوباره دی سریالایز شده و تبدیل به یک Lambda Expression شود. اما سریالایز کردن Lambda Expression واقعا کاری سخت و طاقت فرساست . با توجه به این که در اکثر پروژهها این متدها به صورت Generic نوشته میشوند. برای حل این مسئله بعد از مدتی جستجو، کلاسی رو پیدا کردم که این کار رو برام انجام میداد. بعد از مطالعه دقیق و مشاهده روش کار کلاس، تغییرات مورد نظرم رو اعمال کردم و الان در اکثر پروژه هام دارم از این کلاس استفاده میکنم.
یک مثال از روش استفاده :
برای اینکه از این کلاس در هر دو پروژه (سرور و کلاینت) استفاده میکنیم باید یک Class Library جدید به نام Common بسازید و یک ارجاع از اون رو به هر دو پروژه سمت سرور و کلاینت بدید.
سرویس و Contract بالا رو به صورت زیر باز نویسی کنید.
[ServiceContract] public interface IBookService { [OperationContract] IEnumerable<Book> GetByExpression( XElement expression ); }
using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Xml.Linq; namespace WcfLambdaExpression { public class BookService : IBookService { public BookService() { ListOfBook = new List<Book>(); } public List<Book> ListOfBook { get; private set; } public IEnumerable<Book> GetByExpression( XElement expression ) { ListOfBook.AddRange( new Book[] { new Book(){Code = 1 , Title = "Book1"}, new Book(){Code = 2 , Title = "Book2"}, new Book(){Code = 3 , Title = "Book3"}, new Book(){Code = 4 , Title = "Book4"}, new Book(){Code = 5 , Title = "Book5"}, } ); Common.ExpressionSerializer serializer = new Common.ExpressionSerializer(); return ListOfBook.AsQueryable().Where( serializer.Deserialize( expression ) as Expression<Func<Book, bool>> ); } }
using System; using System.Linq.Expressions; using TestExpression.MyBookService; namespace TestExpression { class Program { static void Main( string[] args ) { BookServiceClient bookService = new BookServiceClient(); Expression<Func<Book, bool>> expression = x => x.Code > 2 && x.Code < 5; Common.ExpressionSerializer serializer = new Common.ExpressionSerializer(); bookService.GetByExpression( serializer.Serialize( expression ) ); } } }
خروجی هم به صورت زیر خواهد بود:
دریافت سورس کامل Expression-Serializationبررسی امنیتی، حین استفاده از jQuery Ajax
- بهتر است بجای اینها از ASP.NET Web API استفاده کنید.
تزریق خودکار وابستگیها در ASP.NET Web API به همراه رها سازی خودکار منابع IDisposable
<Error> <Message> No HTTP resource was found that matches the request URI 'http://localhost:18560/api/TestApi/ForTest'. </Message> <MessageDetail> No action was found on the controller 'TestApi' that matches the request. </MessageDetail> </Error>
WCF Routing Service چیست؟
Routing Service به عنوان سرویس مسیریابی WCF در دات نت 4 معرفی شد. به وسیله Routing Service میتوان Endpoint Configuration مقصدهای مختلف را با هم تجمیع کرد و در نتیجه تعداد تنظیمات برای Endpoint در سمت کلاینت کاهش پیدا میکند به طوری که کلاینت فقط با یک مقصد در ارتباط است. مقصد کلاینت همان Routing Service میباشد که در این سرور درخواستهای رسیده از کلاینتها با توجه به فیلتر انجام شده به مقصد اصلی ارسال خواهند شد.
با استفاده از Routing Service معماری سیستم به صورت تغییر پیدا میکند:
اهداف:
موارد زیر اهداف و مزایای استفاده از Routing Service است:
»Service versioning
»Content-based routing scenario
»Service partitioning
»Protocol bridging
هر کدام از موارد بالا در طی پستهای جداگانه شرح داده خواهند شد.
بررسی یک مثال:
دو Contract به صورت زیر تعریف میکنیم:
[ServiceContract] public interface ICalculatorV1 { [OperationContract] int Add(int a, int b); } [ServiceContract] public interface ICalculatorV2 { [OperationContract] int Sub(int a, int b); }
public class CalculatorV1 : ICalculatorV1 { public int Add(int a, int b) { return a + b; } } public class CalculatorV2 : ICalculatorV2 { public int Sub(int a, int b) { return a - b; } }
system.serviceModel> <services> <service name="WCFRoutingSample.CalculatorV1"> <host> <baseAddresses> <add baseAddress = "http://localhost:8732/CalculatorServiceV1/" /> </baseAddresses> </host> <endpoint address ="" binding="basicHttpBinding" contract="WCFRoutingSample.ICalculatorV1"> <identity> <dns value="localhost"/> </identity> </endpoint> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/> </service> <service name="WCFRoutingSample.CalculatorV2"> <host> <baseAddresses> <add baseAddress = "http://localhost:8733/CalculatorServiceV2/" /> </baseAddresses> </host> <endpoint address ="" binding="basicHttpBinding" contract="WCFRoutingSample.ICalculatorV2"> <identity> <dns value="localhost"/> </identity> </endpoint> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/> </service> </services> <behaviors> <serviceBehaviors> <behavior> <serviceMetadata httpGetEnabled="True"/> <serviceDebug includeExceptionDetailInFaults="False" /> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel>
حال باید RoutingService را به صورت زیر هاست نماییم:
class Program { static void Main(string[] args) { var host = new ServiceHost(typeof(RoutingService)); host.Open(); Console.WriteLine("Server is running."); Console.ReadLine(); host.Close(); } }
مهمترین بخش تنظیمات مربوط به Routing Service است:
<system.serviceModel> <behaviors> <serviceBehaviors> <behavior name="routingBehv"> <routing routeOnHeadersOnly="false" filterTableName="filters"/> <serviceDebug includeExceptionDetailInFaults="true"/> <serviceMetadata httpGetEnabled="true"/> </behavior> </serviceBehaviors> </behaviors> <routing> <filters> <filter name="CalV1ServiceFilter" filterType="EndpointName" filterData="Calv1Service"/> <filter name="CalV2ServiceFilter" filterType="EndpointName" filterData="Calv2Service"/> </filters> <filterTables> <filterTable name="filters"> <add filterName="CalV1ServiceFilter" endpointName="Calv1Service" /> <add filterName="CalV2ServiceFilter" endpointName="Calv2Service"/> </filterTable> </filterTables> </routing> <services> <!-- Routing service with endpoint definition --> <service name="System.ServiceModel.Routing.RoutingService" behaviorConfiguration="routingBehv"> <endpoint address="/Calv1" binding="basicHttpBinding" contract="System.ServiceModel.Routing.IRequestReplyRouter" name="Calv1Service"/> <endpoint address="/Calv2" binding="basicHttpBinding" contract="System.ServiceModel.Routing.IRequestReplyRouter" name="Calv2Service"/> <host> <baseAddresses> <add baseAddress="http://localhost:9000/CalculatorService"/> </baseAddresses> </host> </service> </services> <client> <endpoint address="http://localhost:8732/CalculatorServiceV1" binding="basicHttpBinding" contract="*" name="Calv1Service"/> <endpoint address="http://localhost:8733/CalculatorServiceV2" binding="basicHttpBinding" contract="*" name="Calv2Service"/> </client> </system.serviceModel>
Response.AddHeader("content-disposition", "inline;filename=sample.pdf");
صفحه بندی پویا در Entity Framework
اگر شما در ASP.net استفاد میکنید میتوانی از کنترل ObjectContainerDataSource استفاده کنی که چند مزیت دارد
1 سرعت بالایی دارد
2 امکان sql cache dependency رو فعال میکنه یعنی فقط در هنگامی که شما اطلاعات رو در داخل گرید لود میکنید برای دفعه بعد اگر اطلاعات در دیتابیس تغییری نکرده باشد دیگر به سمت دیتابیس مراجعه نمیکند و اطلاعات از cache خوانده میشود
2 امکان paging سمت سرور رو به شما میدهد .
3 برای پروژهای با دیتای بزرگ تست شده و جواب داده
Here’s a summary of what’s new in this preview release:
- Request decompression middleware
- Output caching middleware
- Updates to rate limiting middleware
- Kestrel support for WebSockets over HTTP/2
- Kestrel performance improvements on high core machines
- Support for logging additional request headers in W3CLogger
- Empty Blazor project templates
- System.Security.Cryptography support on WebAssembly
- Blazor custom elements no longer experimental
- Experimental
QuickGrid
component for Blazor - gRPC JSON transcoding multi-segment parameters
-
MapGroup
support for more extension methods