DTOをWCF RIA Servicesで公開するには
http://weblogs.asp.net/fredriknormen/archive/2009/11/28/wcf-ria-services-and-a-guide-to-use-dto-presentation-model.aspx
上のサイトをみながら試行錯誤してみました。
Entity Frameworkを使うにしても使わないにしてもDTOに変換してクライアント側(Silverlight)に渡すのがシンプルで汎用的でまちがいがないと思いますね。DTOはこんな感じ。
public class Employee { [Key] public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } }
サービスはこんな感じ。DomainServiceを継承します。
[EnableClientAccess()] public class MyDomainService : DomainService { public Employee GetEmployee() { return new Employee() { Id = 1, Name = "Hoge", Age = 30 }; } }
これでビルドすると、クライアント側のSilverlightのプロジェクトにコードが自動生成されます。
ただ、DTOにはSystem.ComponentModel.DataAnnotations.KeyAttributeがないとコード生成が行われませんでした。KeyAttributeが必須なのかもしれない。それか、KeyAttributeでなくても別の方法で目印をつける方法があるのかも。
クライアント側では自動生成されたMyDomainContextを使ってこんな感じでサービスにアクセスできます。
MyDomainContext context = new MyDomainContext(); context.Load(_context.GetEmployeeQuery(), (op) => { if (!op.HasError) { Employee = op.Entities.First(); } }, null);
サーバー側のGetEmployeeに対応するメソッドの名前がGetEmployeeQueryになっています。あんまり理解できてませんが、とりあえず取得できました。
ところで、DTOのプロパティをTwoWayでバインディングして値を変更するとEditできないといった例外が発生しました。
System.NotSupportedException was unhandled by user code Message=This EntitySet of type 'BASample.Web.Models.Employee' does not support the 'Edit' operation. StackTrace: 場所 System.ServiceModel.DomainServices.Client.EntitySet.EnsureEditable(EntitySetOperations operation) 場所 System.ServiceModel.DomainServices.Client.Entity.RaiseDataMemberChanging(String propertyName) 場所 BASample.Web.Models.Employee.set_Name(String value) InnerException:
空のUpdateメソッドを追加したら解決(UpdateAttributeもありますが指定しなくても規約で判定してくれる?)。サーバーサイドで変更するしないに関係なくDTOを変更できていい気がしますが。
[EnableClientAccess()] public class MyDomainService : DomainService { public Employee GetEmployee() { return new Employee() { Id = 1, Name = "Hoge", Age = 30 }; } public void UpdateEmployee(Employee employee) { } }