问题描述

如果你在WCF中用Entity Framework来获取数据并返回实体对象,那么对下面的错误一定不陌生。

接收对 http://localhost:5115/ReService.svc 的 HTTP 响应时发生错误。这可能是由于服务终结点绑定未使用 HTTP 协议造成的。

这还可能是由于服务器中止了 HTTP 请求上下文(可能由于服务关闭)所致。有关详细信息,请参见服务器日志。

这就是因为在返回数据的时候,序列化失败,导致WCF服务自动停止了。

为什么会序列化失败

为了方便说明,我们先做个示例来重现这个错误。

默认情况下,Entity Framework为了支持它的一些高级特性(延迟加载等),默认将自动生成代理类是设置为true,即

      public MyContext(){this.Configuration.ProxyCreationEnabled = true;}

这样,如果我们的实体中包含其它实体的导航属性,则EF会自动的为这个实体生成代理类。

   [DataContract(IsReference=true)]public class Student {public Student(){this.Teachers = new HashSet<Teacher>();}[DataMember]public int ID { get; set; }[DataMember]public virtual string Name { get; set; }[DataMember]public virtual ICollection<Teacher> Teachers { get; set; }}[DataContract(IsReference = true)]public class Teacher{[DataMember]public int ID { get; set; }[DataMember]public virtual string Name { get; set; }}

观察上面两个实体,Student中有对Teacher的导航属性,而Teacher则没有。我们看看通过EF对获取这两个对象有什么不同的情况

我们可以看到EF为Student生成了值为System.Data.Entity.DynamicProxies.Student_...的代理实体

而对于Teacher,返回的就是我们所定义的实体。

如果我们在WCF中分别定义一个契约,来返回这两个实体会怎么样呢?

        [OperationContract]Student GetStudent();[OperationContract]Teacher GetTeacher();

实现方法

     public Student GetStudent(){using (MyContext context = new MyContext()){return context.Students.FirstOrDefault();}}public Teacher GetTeacher(){using (MyContext context = new MyContext()){return context.Teachers.FirstOrDefault();}}

调用 WCF进行测试,我们可以很好的得到GetTeacher()的值,如图

但是,当调用GetStudent()方法,从服务端返回结果到客户端时确报错了。

嗯,没错,就是刚开始我说的那个错误。但,这是为什么呢。我们明明在Student中加了DataContract和DataMember关键字啊。

原因就是EF自动为Student生成了代理类,WCF序列化的其实是EF生成的那个代理类,而不是我们自己定义的Student,而代理类并没有标识这是一个可以序列化的实体。

解决方法

1.禁用代理类

既然原因是EF生成了代理类,那我们把它禁用了就可以了嘛。也很简单,只要将生成代理的配置设置为false即可。

     public MyContext(){this.Configuration.ProxyCreationEnabled = false;}

禁用后,看看通过EF获取Student是怎么样的。

没错,代理类没了,但是我们不能直接通过导航属性来获取Teacher了。这可是杀敌一千,自损八百啊。有没有更好的办法呢?

2 反序列化

既然代理类是由实体序列化而来的,我们就可以在返回数据前将代理类序列化成我们所需要的实体。

   public Student GetStudent(){using (MyContext context = new MyContext()){var stu=context.Students.FirstOrDefault();var serializer = new DataContractSerializer(typeof(Student), new DataContractSerializerSettings(){DataContractResolver = new ProxyDataContractResolver()});using (var stream = new MemoryStream()){// 反序列化serializer.WriteObject(stream, stu);stream.Seek(0, SeekOrigin.Begin);var newStu = (Student)serializer.ReadObject(stream);return newStu;}}}

通过这个方法,再测试一下.

不错,没有报错,并且成功的得到了我们想要的结果。

但每个方法都要这样序列化一下,是不是很麻烦,有没有更好的方法。

答案肯定有,我们可以通过自定义Attribute,加在服务契约上面,标识通过这个服务返回的方法都要进行反序列化。

public class ProxyDataContractResolver: DataContractResolver{private XsdDataContractExporter _exporter = new XsdDataContractExporter();public override Type ResolveName( string typeName,  string typeNamespace,  Type declaredType,DataContractResolver knownTypeResolver){return knownTypeResolver.ResolveName(typeName, typeNamespace, declaredType, null);}public override bool TryResolveType(Type dataContractType,Type declaredType,DataContractResolver knownTypeResolver,out XmlDictionaryString typeName,out XmlDictionaryString typeNamespace){Type  nonProxyType = ObjectContext.GetObjectType(dataContractType);if (nonProxyType != dataContractType){// Type was a proxy type, so map the name to the non-proxy nameXmlQualifiedName qualifiedName = _exporter.GetSchemaTypeName(nonProxyType);XmlDictionary dictionary = new XmlDictionary(2);typeName = new XmlDictionaryString(dictionary,qualifiedName.Name, 0);typeNamespace = new XmlDictionaryString(dictionary,qualifiedName.Namespace, 1);return true;}else{// Type was not a proxy type, so do the defaultreturn knownTypeResolver.TryResolveType(dataContractType,declaredType,null,out typeName,out typeNamespace);}}}

public class ApplyProxyDataContractResolverAttribute : Attribute, IOperationBehavior{public void AddBindingParameters(OperationDescription description, BindingParameterCollection parameters){}public void ApplyClientBehavior(OperationDescription description, ClientOperation proxy){DataContractSerializerOperationBehaviordataContractSerializerOperationBehavior =description.Behaviors.Find<DataContractSerializerOperationBehavior>();dataContractSerializerOperationBehavior.DataContractResolver = new ProxyDataContractResolver();}public void ApplyDispatchBehavior(OperationDescription description, DispatchOperation dispatch){DataContractSerializerOperationBehaviordataContractSerializerOperationBehavior = description.Behaviors.Find<DataContractSerializerOperationBehavior>();dataContractSerializerOperationBehavior.DataContractResolver = new ProxyDataContractResolver();}public void Validate(OperationDescription description){}}

类ApplyProxyDataContractResolverAttribute就是我们想要的结果。现在我们只要在定义服务契约的时候,加上ApplyProxyDataContractResolver关键字就可以了。

        [OperationContract][ApplyProxyDataContractResolver]Student GetStudent();[OperationContract][ApplyProxyDataContractResolver]Teacher GetTeacher();

扩展

对于继承类的序列化,要在基类用KnownType属性来标识

    [KnownType(typeof(ClassB))][KnownType(typeof(ClassA))][DataContract]public class BaseClass{}[DataContract]public class ClassA : BaseClass{}[DataContract]public class ClassB : BaseClass{}

PS:虽然这样可以解决问题,但是多一层序列化会影响效率,希望EF的后续版本可以解决问题吧。

 转自:http://www.cnblogs.com/Gyoung/p/3153875.html

转载于:https://www.cnblogs.com/ITGirl00/p/3533648.html

Entity Framework在WCF中序列化的问题(转)相关推荐

  1. Entity Framework在WCF中序列化的问题

    问题描述 如果你在WCF中用Entity Framework来获取数据并返回实体对象,那么对下面的错误一定不陌生. 接收对 http://localhost:5115/ReService.svc 的 ...

  2. (转)使用Entity Framework和WCF Ria Services开发SilverLight之1:简单模型

    原文地址:http://www.cnblogs.com/luminji/archive/2011/06/10/2077696.html 本文目的是通过Silverlight ria service完成 ...

  3. [转]Using The Entity Framework With WCF

    本文转自:http://www.gavindraper.co.uk/2010/12/07/using-the-entity-framework-with-wcf/ I've had a few pro ...

  4. 在Entity Framework 4.0中使用 Repository 和 Unit of Work 模式

    [原文地址]Using Repository and Unit of Work patterns with Entity Framework 4.0  [原文发表日期] 16 June 09 04:0 ...

  5. Entity Framework 在MySQL中执行SQL语句,关于参数问题

    在Entity Framework中添加MySQL模型,在写代码的过程中需要直接执行SQL语句. 在SQL语句中用到了@curRank := 0 这样在SQL语句中定义参数,同时还会有传入参数:ai. ...

  6. WCF 中序列化自定义依赖属性类

    众所周知.NetFramework中存在着两种依赖属性,他们也分别集成着不同但名称相同的依赖对象: System.Windows.DependencyProperty:System.Windows.D ...

  7. Entity Framework Core 5中实现批量更新、删除

    本文介绍了一个在EntityFramework Core 5中不需要预先加载数据而使用一句SQL语句批量更新.删除数据的开发包,并且分析了其实现原理,并且与其他实现方案做了比较. 一.背景 随着微软全 ...

  8. 使用Entity Framework和WCF Ria Services开发SilverLight之6:查找指定字段

    对数据库表指定字段的查找,又是实际工作中的一项必要工作.SL客户端仅获取实际需要的指定的字段,好处很多,比如:有助于减少网络流量. 有两类这样的使用场景. 1:联表查询不需要外键表 在上一篇中,我们使 ...

  9. Entity Framework 4.3 中的新特性

    原文地址:http://www.cnblogs.com/supercpp/archive/2012/02/20/2354751.html EF4.3于2月9号正式发布了,微软的EF小组最近一年开始发力 ...

最新文章

  1. 妈蛋:kinMaxShow轮播图异常,WebUploader图片上传坑爹,图片被压缩了
  2. ie浏览器修复_继IE之后,微软要彻底放弃它们了...
  3. String hashCode 方法为什么选择数字31作为乘子
  4. python自动化弹框_Python+webdriver自动化脚本弹出框定位
  5. 今日arXiv精选 | 28篇EMNLP 2021最新论文
  6. 读写分离mysql数据库mariadb_MariaDB数据库读写分离实现(一):mysql-proxy的使用
  7. centos下升级g++版本
  8. Python Logging Handler
  9. MongoDB学习day08--Mongoose索引、Mongoose内置方法、扩展Mongoose Model的静态方法和实例方法...
  10. OS开发之Objective-C与JavaScript的交互
  11. 洛谷——P1176 路径计数2
  12. linux下Jdk版本切换
  13. 简单调用exe的方法
  14. php面向对象精要(3)
  15. myeclipse安装使用svn
  16. 使用AD14制作PCB的全部流程以及PCB打样流程介绍
  17. 牛客网 - 编程初学者入门训练 - 分支控制(BC50~BC77)
  18. 高速交警的救命忠告!常跑高速的一定要看!
  19. 新的用户故事待办列表就是一副地图
  20. 【Excel提取数字】用5个简单公式从混合文本中提取数字

热门文章

  1. Apollo进阶课程㊷丨Apollo实战——车辆与循迹驾驶能力实战
  2. html5文件域的自动获取,HTML5 文件域+FileReader 读取文件(一)
  3. html5 sse java_html5----sse实现服务端推送数据给前端
  4. 国开大学计算机应用基础作业二,国家开放大学《计算机应用基础》形考作业二答案解析 (2)...
  5. 关于c语言的英文论文,C语言论文外文翻译.doc
  6. matlab漂亮图表,漂亮,美观的图表之Matlab强势回归~~~~走你8
  7. 从数据库表中随机获取N条记录的SQL语句
  8. leetcode212. 单词搜索 II
  9. c++的虚拟继承 的一些思考吧
  10. C++(16)--运算符重载(自定义Integer类)