Walkthrough: Serialize POCO Proxies with WCF
The POCO proxy type cannot be directly serialized or deserialized by the Windows Communication Foundation (WCF), because the DataContractSerializer serialization engine can only serialize and deserialize known types. The proxy type is not a known type. For more information, see the Serializing POCO Proxies section in the Working with POCO Entities topic. To serialize POCO proxies as POCO entities, use the ProxyDataContractResolver class to map proxy types to POCO types during serialization.
The example in this topic demonstrates how to instruct the DataContractSerializer to use the ProxyDataContractResolver class in service operations by defining an attribute class, which will be applied to the service operations, that internally uses the ProxyDataContractResolver to map proxy types to POCO types. It also shows how to associate the attribute class with methods that are part of a service contract in your WCF application.
The examples in this topic use the POCO classes that are defined in How to: Define POCO Entities and an AdventureWorks-based data model that is defined in How to: Customize Modeling and Mapping Files to Work with Custom Objects.
To create the class library project containing POCO classes.
Create a new class library project named POCOAdventureWorksModel .
Remove the default source code file that was added to the project.
Add an empty model named AdventureWorksModel. To create an empty model, see the To create an empty .edmx file section in the How to: Create a New .edmx File topic. Modify the model by following the steps in Custom AdventureWorks .edmx File.
Disable code generation for the .edmx file. Open the .edmx file in the ADO.NET Entity Data Model Designer (Entity Designer). Right-click on the designer surface and select Properties. In the Properties window, select the Code Generation Strategy property and select None. If the Properties window is not visible, press F4.
Add the app.config file to your class library project. Right-click POCOAdventureWorksModel, click Add, and then click New Item.
In the Add New Item dialog, select General templates and select Application Configuration File. Copy the following code between configuration tags in your application configuration file. Modify the Data Source value if necessary.
<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>
Add a reference to the System.Runtime.Serialization library. This library is needed for the WCF's DataContract and DataMember attributes that are used on the serializable entity types.
Add a new class to your project named
POCOClasses
. Add the code in Serializable POCO Classes Based on the AdventureWorks Model to the file. This contains the entity type and the object context definitions.Compile the project.
To create and configure the WCF project.
Create a WCF Service Application project in the same solution as the class library project named POCOAdventureWorksService.
Add a reference to the System.Data.Entity library.
Add a reference to the POCOAdventureWorksModel project, which is where the model is defined.
Add the connection string to the .config file so the Entity Framework runtime could find the metadata. Open the app.config file in your POCOAdventureWorksModel project, copy the connectionStrings element, and add it as a child element of the configuration element of the Web.config file.
Create a new class and name it
ApplyDataContractResolverAttribute
.Add the following namespaces at the beginning of the file:
using System.Data.Objects; using System.ServiceModel.Description; using System.ServiceModel.Channels;
Replace the code generated for the new class with the following code:
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. } }
Open the service interface file. By default, it is called IService1.
Add the
POCOAdventureWorksModel
namespace at the beginning of the file. This is the namespace where the POCO types are defined.Replace the code that defines the service interface file with the following code:
[ServiceContract] public interface IService1 { [OperationContract] [ApplyDataContractResolver] void UpdateOrder(Order updated); [OperationContract] [ApplyDataContractResolver] Order GetOrder(int OrderID); }
Open the service source code. By default, it is called Service1.srv.cs (or .vb)
Add the
POCOAdventureWorksModel
namespace at the beginning of the file.Replace the code that defines the service class with the following code:
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; } } }
Compile the project.
To test the service.
Create a console application. Type POCOAdventureWorksTest for the project name.
Add a reference to the POCOAdventureWorksModel project.
Add a reference to the POCOAdventureWorksService service. In Solution Explorer, right-click the reference folder and select Add Service Reference.
Open the app.config file and add the connection string to the file. Open the app.config file for POCOAdventureWorksModel, copy the connectionStrings element, and add it as a child element of the configuration element of the Web.config file.
Open the file that contains the main function.
Add the following namespaces, where the service and the POCO types are defined, at the beginning of the file:
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);
Replace the code with the following code. Note, that even though the service was able to serialize POCO proxies, the client received pure POCO objects.
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);