کلاسهای آموزشی (خصوصی)
سایتهای اینترنتی
انجام پروژه
کتاب
استفاده از فیلمهای آموزشی
با توجه به این که دادهها سریالایز میشوند، در نتیجه امکان انقال داده هایی که از نوع 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; } }
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 ); } } }
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
[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با سلام
از نظر قدرت مانور در گزارش گزارش ساز devexpress از سایر ابزارها مثل ssrs , telerik , crystall فوق العاده قوی تره و امکان نمایش دادهها به صورت پدر و فرزندی رو تا n لایه ارائه میده چیزی ، امکان تغذیه گزارش با داده هایی که خود شما میخواید مثل یک iqueryable یا list یا datatable و میتونه کانکشن نداشته باشه و در هر سطحی از گزارش شما امکانات کامل کد نویسی رو برای هر رویدادی در گزارش دارید که فوق العاده است و یک گزارش هم در وب و هم در ویندوز قابل استفاده مجدده ولی مشکلی که هست و باعث شد بنده فعلا با ssrs کار کنم اینه که در وب چیدمان گزارش به هم میخوره که در مثالهای شرکت سازنده چنین چیزی دیده نمیشه - رتبه دوم متعلق به ssrs هست که ابزاری پر قدرت با قابلیت برنامه نویسی توکار vb.net و درج هر گونه کتابخانه خارجی در صورت نیاز است ، تا اونجایی که بنده اطلاع دارم telerik یکی از ضعبفترین نوع گزارشات رو در بین بقیه شرکتها ارائه میده
#include <iostream>
int main() { return 0; }
std::cout<<"Hello world ...\n";
قصد دارم مجموعه ای کامل از اصول طراحی شیء گرا، الگوهای طراحی و best practice های مربوطه را ارائه دهم. از این رو ابتدا با اصول طراحی شروع میکنم. سپس در مقالات آتی به الگوهای مختلف خواهم پرداخت و تا جایی که معلومات اجازه دهد مشخص خواهم کرد که هر الگو متمرکز بر رعایت کدام یک از اصول است و اینکه آیا مناسب است از الگوی مورد نظر استفاده کنیم.
این مطالب نیز چکیده ای از آموزشهای Lynda, Pluralsight , SkillFeed و کتاب های Gang of four, Headfirst Design
patterns و ...
میباشد .
اصل اول: Encapsulate what varies
"آنچه را که تغییر میکند مشخص و جدا کن یا به عبارتی آنرا کپسوله کن"
برای آنکه بتوانیم کدی منعطف،
قابل استفاده مجدد و خوانا داشته باشیم، ابتدا باید بخشهای ثابت و متغیر کد را تشخیص
دهیم و کاری کنیم تا بخش ثابت، بدون تکرار در جای جای برنامه استفاده شود و سپس برای بخش
متغیر برنامه ریزی کنیم.
اصل دوم: Program to an interface not implementation
" برنامه نویسی را متمرکز بر واسط کن، نه نحوهی پیاده سازی "
برای این اصل تعابیر مختلفی ارائه شده است:
برای رعایت این اصل باید:
در کد زیر نحوهی تعریف واسط را برای کلاس و تعریف اشیاء از نوع واسط را میبینیم:
public interface IMyInterface { void DoWork(); } public class MyImplementation1 : IMyInterface { public void DoWork() { var implementationName = this.GetType().ToString(); Console.WriteLine("DoWork from " + implementationName); } } public class MyImplementation2 : IMyInterface { public void DoWork() { var implementationName = this.GetType().ToString(); Console.WriteLine("DoWork from " + implementationName); } } public class Context { IMyInterface myInterface; public void Print() { myInterface = new MyImplementation1(); myInterface.DoWork(); myInterface = new MyImplementation2(); myInterface.DoWork(); } }
اصل سوم: Favor composition over inheritance
"ترکیب را بر توارث ترجیح بده"
رابطه "دارد" (has a ) انعطاف بیشتری نسبت به ارث بری یا "از نوع ... هست" ( is a ) دارد. برای مثال فرض کنید کلاس Enemy رفتار Movable را دارد و این رفتار در طول بازی بر حسب موقعیتی تغییر میکند. اگر این رفتار را با توارث مدل کنیم، یعنی Enemy از نوع Movable باشد، آنگاه برای هر نوع رفتار Movable (هر نوع پیاده سازی) باید یک نوع Enemy داشته باشیم و تصور کنید بعضی از این پیاده سازیها در کلاس Player یکسان باشد. آنگاه کد باید دوباره تکرار شود. حال تصور کنید این موقعیت را با ترکیب مدل کنیم. آنگاه کلاس Enemy یک شیء از جنس Movable خواهد داشت و در زمان نیاز میتواند نوع این رفتار را با نمونه گیری از کلاسهای پیاده ساز آن، تغییر دهد. در واقع با اینکار اصل اول را رعایت کرده ایم و بخش ثابت را از بخش متغیر جدا نموده ایم.
در زیر مدلسازی با توارث را میبینیم:
public interface Movable { void Move(); } public class EnemyBase : Movable { // Enemy properties goes here protected int x, y; public virtual void Move() { x += 2; y += 2; } } public class EnemyWithMoveType2 : EnemyBase { // override the move method public override void Move() { x += 4; y += 4; } } public class EnemyWithMoveType3 : EnemyBase { // override the move method public override void Move() { x += 6; y += 6; } } public class PlayerBase : Movable { // Player properties goes here protected int x, y; public virtual void Move() { // same code as EnemyBase move method x += 2; y += 2; } } public class PlayerWithMoveType2 : PlayerBase { // override the move method public override void Move() { // same code as EnemyWithMoveType2 move method x += 4; y += 4; } } public class PlayerWithMoveType3 : PlayerBase { // override the move method public override void Move() { // same code as EnemyWithMoveType3 move method x += 6; y += 6; } }
در ادامه نیز مدلسازی با ترکیب را میبینیم:
public interface IMovable { void Move(ref int x, ref int y); } public class EnemyBase { // Enemy properties goes here protected int x, y; IMovable moveBehavior; public void SetMoveBehavior(IMovable _moveBehavior) { moveBehavior = _moveBehavior; } public void Move() { moveBehavior.Move(ref x,ref y); } } public class PlayerBase { // Player properties goes here protected int x, y; IMovable moveBehavior; public void SetMoveBehavior(IMovable _moveBehavior) { moveBehavior = _moveBehavior; } public void Move() { moveBehavior.Move(ref x, ref y); } } public class MoveBehavior1 { public void Move(ref int x, ref int y) { x += 2; y += 2; } } public class MoveBehavior2 : IMovable { public void Move(ref int x, ref int y) { x += 4; y += 4; } } public class MoveBehavior3 : IMovable { public void Move(ref int x, ref int y) { x += 6; y += 6; } }
همانطور که میبینید، با فراخوانی تابع SetMoveBehavior میتوان رفتار را در زمان اجرا تغییر داد.
در مقالهی بعدی به ادامهی اصول خواهم پرداخت. از شنیدن نظرات و سوالات شما خرسند خواهم شد.
public async Task<Maybe<Post>> FindByIdAsync(Guid id) { Maybe<Post> post = await _posts.FindAsync(id); return post; }
public async Task<Result> DeletePost(Guid id) { return await FindByIdAsync(id) .ToResult("پست مورد نظر یافت نشد.") .OnSuccess(x => _posts.Remove(x)) .OnSuccess(x => _unitOfWork.SaveChangesAsync()) .OnBoth(x => x.IsSuccess ? Result.Ok() : Result.Fail(x.Error)); }