zoukankan      html  css  js  c++  java
  • Entity Framework 6 Recipes 2nd Edition(9-7)译->在WCF服务中序列化代理

    9-7. 在WCF服务中序列化代理

    问题

    从一个查询里返回一个动态代理对象,想要把它序列为一个POCO(Plain-Old CLR Objects)对象.

    实现基于POCO实体对象, 在运行时,EF会为每个实体自动生成一个派生类型,被称为动态代理对象,

    代理对象会为POCO类重载很多虚拟属性来注入执行操作的挂钩,像变更跟踪,和延迟加载关联的实体。

    解决方案

    假设我们有一个如Figure 9-7.所示的客户模型

     

    Figure 9-7. 客户模型

    我们将使用ProxyDataContractResolver类在服务端把一个代理对象反序列化为Client的POCO类

    1. 创建Wcf服务应用程序.添加一个ADO.NET实体数据模型,并选择”Client”表,创建好的模型,就如 Figure 9-7.所示.

    2.打开Client的 POCO类, 为每个属性添加virtual关键字,如Listing 9-33所示 . 这样EF就可以创建动态代理类了。

    ============================================================================================

    ■■注意:如果你修改EDMX文件,EF会自动重新生成类,会重写第2步里你对类的修改,你可以再次修改类或是修改T4模板来生成实体代码。

    =======================================================================

    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.我们需要为DataContractSerializer使用ProxyDataContractResolver类为WCF服务的客户端把client 代理转换为client实例.为此我们将创建一个操作行为特性 ,并且让GetClient() 方法使用这个特性。新特性的代码如 Listing 9-34 所示.注意:ProxyDataContractResolver 类属于EF命名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.用Listing 9-35里的代码修改IService1.cs 接口

    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. 用Listing 9-36里的代码修改Service1.svc.cs 文件来实现服务接口。

    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())

                {

                    //删除之前的测试数据

                    context.Database.ExecuteSqlCommand("delete from chapter9.client");

                    //插入新的测试数据

                    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.在解决方案中添加一个新的Windows控制台应用程序,这是我们用来测试的客户端,代码如

    Listing 9-37所示,添加WCF的引用。

    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(" press any key to exit...");

                    Console.ReadKey(true);

                }

            }

    }

    以下是控制台输出结果:

    ===================================================================

    Client is: Jerry Jones at jjones@gmail.com

    Client changed to: Alex Park at AlexP@hotmail.com

    =================================================================================

    它是如何工作的?

    微软建议为WCF使用POCO对象,方便序列化实体对象。如果我们的应用程序使用POCO对象,并支持变更通知(把属性设为virtual and导航对象集合类型为ICollection), EF会为从查询返回的实体创建动态代理。这里有两个关于动态代理和WCF的问题,第一个问题是:必须序列化代理。 而DataContractSerializer 只能序列化和反序列化已知的类型,例如我们例子中的Client实体.然而 EF为Client 实体自动生成一个动态代理类,我们需要序列化这个代理类, 而不是 Client类,DataContractResolver就是解决这个问题的. 它能在序列化期间把一个类型映射到另一个类型. ProxyDataContractResolver 来源于DataContractResolver 并映射代理类型到 POCO类, 例如我们的 Client 实体. 为了使用ProxyDataContractResolver, 我们创建特性 (见 Listing 9-34) 来解决代理转换成POCO类.我们在GetClient()方法上应用这个特性 (见Listing 9-36). 这样Client实体的动态代理能正确的序列化,并被GetClient() 返回给WCF服务的调用者。第二个问题:必须处理延迟加载的问题.当  DataContractSerializer 序列化实体时, 它访问实体的每个属性,这会触发延迟加载导航属性. 这当然不是我们所希望的,所以我们要关闭延迟加载,如Listing 9-36所示。

    附:创建示例用到的数据库的脚本文件

    kid1412声明:转载请把此段声明完整地置于文章页面明显处,并保留个人在博客园的链接:http://www.cnblogs.com/kid1412/(可点击跳转)。

  • 相关阅读:
    spring.jar的下载地址
    spring学习(1)
    供求信息网(2)
    编写学生增删改查系统时碰到的问题
    js中innerText/value/innerHTML三个属性的区别
    form的提交方式
    错误记录(1)
    供求信息网
    GYM 101673F(树计数)
    GYM 101673G(dp)
  • 原文地址:https://www.cnblogs.com/kid1412/p/5143585.html
Copyright © 2011-2022 走看看