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("\npress 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所示。

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

Entity Framework 6 Recipes 2nd Edition(9-7)译->在WCF服务中序列化代理的更多相关文章

  1. Entity Framework 6 Recipes 2nd Edition 译 -> 目录 -持续更新

    因为看了<Entity Framework 6 Recipes 2nd Edition>这本书前面8章的翻译,感谢china_fucan. 从第九章开始,我是边看边译的,没有通读,加之英语 ...

  2. Entity Framework 6 Recipes 2nd Edition(9-1)译->用Web Api更新单独分离的实体

    第九章 在N层结构的应用程序中使用EF 不是所有的应用都能完全地写入到一个单个的过程中(就是驻留在一个单一的物理层中),实际上,在当今不断发展的网络世界,大量的应用程序的结构包含经典的表现层,应用程, ...

  3. Entity Framework 6 Recipes 2nd Edition(9-3)译->找出Web API中发生了什么变化

    9-3. 找出Web API中发生了什么变化 问题 想通过基于REST的Web API服务对数据库进行插入,删除和修改对象图,而不必为每个实体类编写单独的更新方法. 此外, 用EF6的Code Fri ...

  4. Entity Framework 6 Recipes 2nd Edition(9-4)译->Web API 的客户端实现修改跟踪

    9-4. Web API 的客户端实现修改跟踪 问题 我们想通过客户端更新实体类,调用基于REST的Web API 服务实现把一个对象图的插入.删除和修改等数据库操作.此外, 我们想通过EF6的Cod ...

  5. Entity Framework 6 Recipes 2nd Edition(13-2)译 -> 用实体键获取一个单独的实体

    问题 不管你用DBFirst,ModelFirst或是CodeFirst的方式,你想用实体键获取一个单独的实体.在本例中,我们用CodeFirst的方式. 解决方案 假设你有一个模型表示一个Paint ...

  6. Entity Framework 6 Recipes 2nd Edition(13-3)译 -> 为一个只读的访问获取实体

    问题 你想有效地获取只是用来显示不会更新的操作的实体.另外,你想用CodeFirst的方式来实现 解决方案 一个非常常见行为,尤其是网站,就是只是让用户浏览数据.大多数情况下,用户不会更新数据.在这种 ...

  7. Entity Framework 6 Recipes 2nd Edition(13-4)译 -> 有效地创建一个搜索查询

    问题 你想用LINQ写一个搜索查询,能被转换成更有效率的SQL.另外,你想用EF的CodeFirst方式实现. 解决方案 假设你有如下Figure 13-6所示的模型 Figure 13-6. A s ...

  8. Entity Framework 6 Recipes 2nd Edition(13-5)译 -> 使POCO的修改追踪更高

    问题 你正在使用POCO,你想提高修改跟踪的性能,同时使内存消耗更少.另外,你想通过EF的CodeFirst方式来实现. 解决方案 假设你有一个关于Account(帐户)和相关的Payments(支付 ...

  9. Entity Framework 6 Recipes 2nd Edition(13-9)译 -> 避免Include

    问题 你想不用Include()方法,立即加载一下相关的集合,并想通过EF的CodeFirst方式实现. 解决方案 假设你有一个如Figure 13-14所示的模型: Figure 13-14. A ...

随机推荐

  1. 一起学 Java(三) 集合框架、数据结构、泛型

    一.Java 集合框架 集合框架是一个用来代表和操纵集合的统一架构.所有的集合框架都包含如下内容: 接口:是代表集合的抽象数据类型.接口允许集合独立操纵其代表的细节.在面向对象的语言,接口通常形成一个 ...

  2. Android权限管理之Permission权限机制及使用

    前言: 最近突然喜欢上一句诗:"宠辱不惊,看庭前花开花落:去留无意,望天空云卷云舒." 哈哈~,这个和今天的主题无关,最近只要不学习总觉得生活中少了点什么,所以想着围绕着最近面试过 ...

  3. 引人瞩目的 CSS 变量(CSS Variable)

    这是一个令人激动的革新. CSS 变量,顾名思义,也就是由网页的作者或用户定义的实体,用来指定文档中的特定变量. 更准确的说法,应该称之为 CSS 自定义属性 ,不过下文为了好理解都称之为 CSS 变 ...

  4. angular2系列教程(七)Injectable、Promise、Interface、使用服务

    今天我们要讲的ng2的service这个概念,和ng1一样,service通常用于发送http请求,但其实你可以在里面封装任何你想封装的方法,有时候控制器之间的通讯也是依靠service来完成的,让我 ...

  5. 算法与数据结构(十六) 快速排序(Swift 3.0版)

    上篇博客我们主要聊了比较高效的归并排序算法,本篇博客我们就来介绍另一种高效的排序算法:快速排序.快速排序的思想与归并排序类似,都是采用分而治之的方式进行排序的.快速排序的思想主要是取出无序序列中第一个 ...

  6. Log4net - 规则简介

    参考页面: http://www.yuanjiaocheng.net/CSharp/csharprumenshili.html http://www.yuanjiaocheng.net/entity/ ...

  7. [原创]java使用JDBC向MySQL数据库批次插入10W条数据测试效率

    使用JDBC连接MySQL数据库进行数据插入的时候,特别是大批量数据连续插入(100000),如何提高效率呢?在JDBC编程接口中Statement 有两个方法特别值得注意:通过使用addBatch( ...

  8. spider RPC入门指南

    本部分将介绍使用spider RPC开发分布式应用的客户端和服务端. spider RPC中间件基于J2SE 8开发,因此需要确保服务器上安装了JDK 8及以上版本,不依赖于任何额外需要独立安装和配置 ...

  9. jquery.multiselect 多选下拉框实现

    第一步:链接下列文件,如果没有,到此网页下载 https://github.com/ehynds/jquery-ui-multiselect-widget,此插件基于jquery ,所以jquery的 ...

  10. Centos6.5 配置Nginx开机自启动

    1.在/etc/init.d/目录下创建 nginx 文件,内容如下: #!/bin/sh # # nginx - this script starts and stops the nginx dae ...