Entity Framework 6 Recipes 2nd Edition (9-7) Translation-> serialize proxy in the WCF Service, recipeswcf
9-7. serialize the proxy in the WCF Service
Problem
Returns a dynamic proxy object from a query, and wants to sequence it into a POCO (Plain-Old CLR Objects) object.
Implemented based on POCO object. At runtime, EF automatically generates a derived type for each object, which is called a dynamic proxy object,
The proxy object will reload many virtual attributes for the POCO class to inject the hooks for executing operations, such as change tracking and delayed loading of associated entities.
Solution
Suppose we have a customer model shown in Figure 9-7.
Figure 9-7.Customer Model
We will useProxyDataContractResolverClass deserializes a proxy object to the POCO class of the Client on the server end
1. Create a Wcf Service Application. Add an ADO. NET object data model and select the "Client" table. The created model is shown in Figure 9-7.
2. Open the POCO class of the Client and add the virtual keyword for each attribute, as shown in Listing 9-33. In this way, EF can create a dynamic proxy class.
========================================================== ========================================================== ================
■Note: If you modifyEDMXFile,EFThe class is automatically regenerated and2You can modify the class again orT4Template to generate entity code.
========================================================== ====================================
Listing 9-33.Our Client POCO Class and Our Object Vontext
Public partial class Client
{
Public virtual int ClientId {get; set ;}
Public virtual string Name {get; set ;}
Public virtual string Email {get; set ;}
}
3. we need to use the ProxyDataContractResolver class for the client of DataContractSerializer to convert the client proxy to the client instance for the client of the WCF Service. therefore, we will create an operation behavior feature and use this feature for the GetClient () method. The code for the new feature is shown in Listing 9-34. Note: The ProxyDataContractResolver class belongs to the EF class named System. Data. Entity. Core. Objects.
Listing 9-34.Our Custom Operation Behavior Attribute
Namespace Recipe7
{
Public class ApplyProxyDataContractResolverAttribute:
Attribute, IOperationBehavior
{
Public void AddBindingParameters (OperationDescription description,
BindingParameterCollection parameters)
{
}
Public void ApplyClientBehavior (OperationDescription description, ClientOperation proxy)
{
DataContractSerializerOperationBehavior dataContractSerializerOperationBehavior =
Description. Behaviors. Find <DataContractSerializerOperationBehavior> ();
DataContractSerializerOperationBehavior. DataContractResolver =
New ProxyDataContractResolver ();
}
Public void Validate (OperationDescription description)
{
}
Public void ApplyDispatchBehavior (OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
DataContractSerializerOperationBehavior
DataContractSerializerOperationBehavior =
OperationDescription. Behaviors. Find <DataContractSerializerOperationBehavior> ();
DataContractSerializerOperationBehavior. DataContractResolver = new ProxyDataContractResolver ();
}
}
}
4. Use the code in Listing 9-35 to modify the IService1.cs Interface
Listing 9-35.Our IService1 Interface Definition, Which Replaces the Code in IService1.cs
[ServiceContract]
Public interface IService1
{
[OperationContract]
Void InsertTestRecord ();
[OperationContract]
Client GetClient ();
[OperationContract]
Void Update (Client client );
}
5. Use the code in Listing 9-36 to modify the Service1.svc. cs file to implement the service interface.
Listing 9-36.The Implementation of the IService1 Interface, Which Replaces the Code in IService1.svc. cs
Public class Service1: IService1
{
Public void InsertTestRecord ()
{
Using (var context = new EFRecipesEntities ())
{
// Delete the previous test data
Context. Database. ExecuteSqlCommand ("delete from chapter9.client ");
// Insert new test data
Context. Database. ExecuteSqlCommand (@ "insert into chapter9.client (name, email) values ('Jerry Jones ', 'jjones @ gmial.com ')");
}
}
[ApplyProxyDataContractResolver]
Public Client GetClient ()
{
Using (var context = new EFRecipesEntities ())
{
Context. Configuration. LazyLoadingEnabled = false;
Return context. Clients. Single ();
}
}
Public void Update (Client client)
{
Using (var context = new EFRecipesEntities ())
{
Context. Entry (client). State = EntityState. Modified;
Context. SaveChanges ();
}
}
}
6. Add a new Windows console application in the solution. This is the client we use to test. The Code is as follows:
Add a reference to WCF, as shown in Listing 9-37.
Listing 9-37.Our Windows console application test client
Class Program
{
Static void Main (string [] args)
{
Using (var serviceClient = new ServiceReference1.Service1Client ())
{
ServiceClient. InsertTestRecord ();
Var client = serviceClient. GetClient ();
Console. WriteLine ("Client is: {0} at {1}", client. Name, client. Email );
Client. Name = "Alex Park ";
Client. Email = "AlexP@hotmail.com ";
ServiceClient. Update (client );
Client = serviceClient. GetClient ();
Console. WriteLine ("Client changed to: {0} at {1}", client. Name, client. Email );
Console. WriteLine ("\ npress any key to exit ...");
Console. ReadKey (true );
}
}
}
The following is the output result of the console:
========================================================== ======================================
Client is: Jerry Jones at jjones@gmail.com
Client changed to: Alex Park at AlexP@hotmail.com
========================================================== ========================================================== =
How does it work?
Microsoft recommends using POCO objects for WCF to facilitate Object serialization. If our application uses POCO objects and supports change notification (set the property to virtual and navigation object collection type to ICollection), EF will create a dynamic proxy for the objects returned from the query. There are two issues about dynamic proxy and WCF. The first problem is that the agent must be serialized. DataContractSerializer can only serialize and deserialize known types, for example, the Client entity in our example. however, EF automatically generates a dynamic proxy class for the Client object. We need to serialize this proxy class, instead of the Client class. DataContractResolver solves this problem. it can map one type to another during serialization. proxyDataContractResolver comes from DataContractResolver and maps the proxy type to the POCO class, for example, our Client entity. to use ProxyDataContractResolver, we create features (see Listing 9-34) to resolve proxy conversion to POCO class. we apply this feature on the GetClient () method (see Listing 9-36 ). in this way, the dynamic proxy of the Client object can be correctly serialized and is returned to the WCF by GetClient (). Service caller. The second problem: the problem of delayed loading must be solved. when DataContractSerializer serializes an object, it accesses each attribute of the object, which triggers delayed loading of navigation attributes. this is certainly not what we want, so we need to disable delayed loading, as shown in Listing 9-36.
Appendix: script file of the database used in the Creation example