• Entity Framework + WCF 远程调用出错


            在使用Entity Framework中使用WCF,在程序中调用服务一直报错,我一直以为是WCF的哪个地方的配置有问题,找来找去,一直没有解决。

    image

            最后在网上找到一篇文章,说是序列化的问题,我才想起来,原来是跟Entity Framework有关。又是导航属性序列化的问题。觉得真是坑爹,早该想到的。

           分析出来,还是因为实体类中有导航属性,而EF会为有导航属性的实体类,生成一个代理类,而这个代理类也有自引用。所以WCF在序列化的时候,就会出错。报的就是上面的这个错误。

            一种办法说是禁用生成代理,这个是可以实现的,直接在Context里面禁用就可以了。

    this.Configuration.ProxyCreationEnabled = false;
            但是如果禁用代理了,就不能通过导航属性得到关联的值了。所以这个方法不可行。在网上找到的另外一种办法就是自定义一个特性。个人开始嫌麻烦,不愿意自定义这个特性。

            我想是不是因为有这个导航属性才这样的,所以最开始想能不能让这个导航属性字段不序列化,只序列化其他的字段应该就行了,因为我前台并不需要用到这个导航属性。我在实体里面把导航属性前面的DataMember特性去掉了,最后发现还是报这个错误。后来设计发现,就算把这个特性去掉了,只是代表不序列化,但是这个属性还是有virtual关键字,EF框架还是会为它生成代理类。之所以WCF报错不是因为导航属性序列化的问题,而是因为有导航属性字段,会生成代理类。是代理类的序列化出了问题。

           最后还是参照网上的方法,自定义一个特性,然后在接口方法上应用这个特性,才把这个问题解决了。

           自定义特性的代码是:

            先定义一个类ProxyDataContractResolver:

    //DataContractResolver在System.Runtime.Serialization这个命名空间里
    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 name
                XmlQualifiedName 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 default
                return knownTypeResolver.TryResolveType(
                                          dataContractType,
                                          declaredType,
                                          null,
                                          out typeName,
                                          out typeNamespace);
            }
        }
    }

         再定义一个特性类ApplyProxyDataContractResolverAttribute

    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 ApplyDispatchBehavior(OperationDescription description, DispatchOperation dispatch)
        {
            DataContractSerializerOperationBehavior
                       dataContractSerializerOperationBehavior = description.Behaviors.Find<DataContractSerializerOperationBehavior>();
            dataContractSerializerOperationBehavior.DataContractResolver = new ProxyDataContractResolver();
        }
        public void Validate(OperationDescription description)
        {
        }
    }

          然后在接口层的方法上面加上这个特性就可以了。

    [OperationContract]
    [ApplyProxyDataContractResolverAttribute]

           终于可以松一口气了,在使用EF的过程中,一定要考虑到这个导航属性的特殊性。

    参考文章:

    http://www.cnblogs.com/Gyoung/p/3153875.html(文中的代码都是摘自这篇文章,谢谢!)

  • 相关阅读:
    维护电池检测上位机软件
    20192412 202120222 《网络与系统攻防技术》实验二实验报告
    20192412 202120222 《网络与系统攻防技术》实验三实验报告
    qps、并发数
    找最大字母
    常见的垃圾回收器和使用的场景
    2192. 有向无环图中一个节点的所有祖先
    reetrantlock和synchronize的区别
    flink两阶段提交
    kafka为什么适合大数据场景?
  • 原文地址:https://www.cnblogs.com/xiaoxiangfeizi/p/3539926.html
Copyright © 2020-2023  润新知