チュートリアル: WCF による POCO プロキシのシリアル化 (Entity Framework)
DataContractSerializer シリアル化エンジンは既知の型しかシリアル化と逆シリアル化ができないため、POCO プロキシ型を Windows Communication Foundation (WCF) で直接シリアル化または逆シリアル化することはできません。 プロキシ型は既知の型ではありません。 詳細については、トピック「POCO エンティティの使用 (Entity Framework)」の「POCO プロキシのシリアル化」セクションを参照してください。 POCO プロキシを POCO エンティティとしてシリアル化するには、シリアル化中に ProxyDataContractResolver クラスを使用してプロキシ型を POCO 型にマップします。
このトピックの例は、属性クラスを定義してサービス操作で ProxyDataContractResolver クラスを使用するように DataContractSerializer に指示する方法を紹介します。これはサービス操作に適用され、内部で ProxyDataContractResolver を使用してプロキシ型を POCO 型にマッピングします。 また、WCF アプリケーション内のサービス コントラクトの一部であるメソッドに、この属性クラスを関連付ける方法も示します。
このトピックの例では、方法: POCO エンティティを定義する (Entity Framework) で定義されている POCO クラスと、カスタム オブジェクトを操作できるようにモデリング ファイルとマッピング ファイルをカスタマイズする方法 (Entity Framework) で定義されている AdventureWorks ベースのデータ モデルを使用します。
POCO クラスを含むクラス ライブラリ プロジェクトを作成するには
POCOAdventureWorksModel という名前の新しいクラス ライブラリ プロジェクトを作成します。
プロジェクトに追加された既定のソース コード ファイルを削除します。
AdventureWorksModel という名前の空のモデルを追加します。 空のモデルを作成するには、「How to: Create a New .edmx File」の「空の .edmx ファイルを作成するには」を参照してください。 「カスタム AdventureWorks .edmx ファイル (Entity Framework)」の手順に従ってモデルを変更します。
.edmx ファイルのコード生成を無効にします。 ADO.NET Entity Data Model Designer (エンティティ デザイナー) で .edmx ファイルを開きます。 デザイナー画面を右クリックして [プロパティ] をクリックします。 [プロパティ] ウィンドウで、[コード生成方法] プロパティをクリックし、None をクリックします。 [プロパティ] ウィンドウが表示されない場合は、F4 キーを押してください。
app.config ファイルをクラス ライブラリ プロジェクトに追加します。 [POCOAdventureWorksModel] を右クリックし、[追加] をクリックして、[新しい項目] をクリックします。
[新しい項目の追加] ダイアログで、[全般] テンプレートを選択し、[アプリケーション構成ファイル] を選択します。 アプリケーション構成ファイルの configuration タグの間に次のコードをコピーします。 必要に応じて Data Source の値を変更します。
<connectionStrings> <add name="AdventureWorksEntities" connectionString="metadata=res://*/AdventureWorksModel.csdl|res://*/AdventureWorksModel.ssdl|res://*/AdventureWorksModel.msl; provider=System.Data.SqlClient;provider connection string=" Data Source=(local);Initial Catalog=AdventureWorks; Integrated Security=True;MultipleActiveResultSets=True"" providerName="System.Data.EntityClient" /> </connectionStrings>
System.Runtime.Serialization ライブラリへの参照を追加します。 このライブラリは、シリアル化可能なエンティティ型で使用される WCF のDataContract 属性と DataMember 属性に必要です。
POCOClasses
という名前の新しいクラスをプロジェクトに追加します。 AdventureWorks モデルに基づくシリアル化可能な POCO クラス のコードをファイルに追加します。 これにはエンティティ型とオブジェクト コンテキストの定義が含まれています。プロジェクトをコンパイルします。
WCF プロジェクトを作成して構成するには
同じソリューションで WCF Service Application プロジェクトを、POCOAdventureWorksService という名前のクラス ライブラリ プロジェクトとして作成します。
System.Data.Entity ライブラリへの参照を追加します。
POCOAdventureWorksModel プロジェクトへの参照を追加します。これはモデルを定義する場所です。
Entity Framework ランタイムがメタデータを検出できるように、.config ファイルに接続文字列を追加します。 POCOAdventureWorksModel プロジェクトの app.config ファイルを開き、connectionStrings 要素をコピーし、Web.config ファイルの configuration 要素の子要素として追加します。
新しいクラスを作成し、
ApplyDataContractResolverAttribute
という名前を付けます。ファイルの先頭に次の名前空間を追加します。
using System.Data.Objects; using System.ServiceModel.Description; using System.ServiceModel.Channels;
新しいクラスに生成されたコードを次のコードに置き換えます。
public class ApplyDataContractResolverAttribute : Attribute, IOperationBehavior { public ApplyDataContractResolverAttribute() { } public void AddBindingParameters(OperationDescription description, BindingParameterCollection parameters) { } public void ApplyClientBehavior(OperationDescription description, System.ServiceModel.Dispatcher.ClientOperation proxy) { DataContractSerializerOperationBehavior dataContractSerializerOperationBehavior = description.Behaviors.Find<DataContractSerializerOperationBehavior>(); dataContractSerializerOperationBehavior.DataContractResolver = new ProxyDataContractResolver(); } public void ApplyDispatchBehavior(OperationDescription description, System.ServiceModel.Dispatcher.DispatchOperation dispatch) { DataContractSerializerOperationBehavior dataContractSerializerOperationBehavior = description.Behaviors.Find<DataContractSerializerOperationBehavior>(); dataContractSerializerOperationBehavior.DataContractResolver = new ProxyDataContractResolver(); } public void Validate(OperationDescription description) { // Do validation. } }
サービス インターフェイス ファイルを開きます。 このファイルは既定では IService1 と呼ばれます。
コード ファイルの先頭に
POCOAdventureWorksModel
名前空間を追加します。 これは、POCO 型が定義される名前空間です。サービス インターフェイス ファイルを定義するコードを次のコードに置き換えます。
[ServiceContract] public interface IService1 { [OperationContract] [ApplyDataContractResolver] void UpdateOrder(Order updated); [OperationContract] [ApplyDataContractResolver] Order GetOrder(int OrderID); }
サービス ソース コードを開きます。 このファイルは既定では Service1.srv.cs (または .vb) と呼ばれます。
コード ファイルの先頭に
POCOAdventureWorksModel
名前空間を追加します。サービス クラスを定義するコードを次のコードに置き換えます。
public class Service1 : IService1 { public void UpdateOrder(Order updated) { using (POCOAdventureWorksEntities context = new POCOAdventureWorksEntities()) { // Attach the original order to the context by querying the database. // Alternatively, you can require that the updated object be returned along with the original object from the client. // This means the client would need to clone the original object. Order original = context.Orders.SingleOrDefault(o => o.SalesOrderID == updated.SalesOrderID); // Apply changes to the order object. context.Orders.ApplyCurrentValues(updated); context.SaveChanges(); } } public Order GetOrder(int OrderID) { using (POCOAdventureWorksEntities context = new POCOAdventureWorksEntities()) { // You can disable the proxy creation // by setting context.ContextOptions.ProxyCreationEnabled to false context.ContextOptions.LazyLoadingEnabled = false; // The order was created as a POCO proxy object. // But it will be recieved on the client as a pure POCO. Order order = context.Orders.SingleOrDefault(o => o.SalesOrderID == OrderID); return order; } } }
プロジェクトをコンパイルします。
サービスをテストするには
コンソール アプリケーションを作成します。 プロジェクト名の「POCOAdventureWorksTest」を入力します。
POCOAdventureWorksModel への参照をプロジェクトに追加します。
POCOAdventureWorksService サービスへの参照を追加します。 ソリューション エクスプローラーで、参照フォルダーを右クリックし、[サービス参照の追加] を選択します。
app.config ファイルを開き、接続文字列をファイルに追加します。 POCOAdventureWorksModel の app.config ファイルを開き、connectionStrings 要素をコピーし、Web.config ファイルの configuration 要素の子要素として追加します。
main 関数を含んでいるファイルを開きます。
サービスと POCO 型が定義される次の名前空間をファイルの先頭に追加します。
Service1Client client = new Service1Client(); int orderId = 43680; Order order = client.GetOrder(orderId); Console.WriteLine(order.DueDate); // Modify order. order.DueDate = DateTime.Now; // Update order in the database. client.UpdateOrder(order);
このコードを次のコードに置き換えます。 サービスは POCO プロキシをシリアル化できましたが、クライアントは純粋の POCO オブジェクトを受け取りました。
Service1Client client = new Service1Client(); int orderId = 43680; Order order = client.GetOrder(orderId); Console.WriteLine(order.DueDate); // Modify order. order.DueDate = DateTime.Now; // Update order in the database. client.UpdateOrder(order);