日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Entity Framework在WCF中序列化的问题(转)

發布時間:2023/12/18 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Entity Framework在WCF中序列化的问题(转) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

問題描述?

如果你在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中序列化的问题(转)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。