Asp.Net MVC + WCF (2) EF树节点对象WCF传输问题

6 篇文章 0 订阅

在以前也碰到过EF对象用WCF传输的问题(WCF开发(8) EF),主要是通过DbSet获取的对象,默认情况下不是我们自己定义的类对象,而是动态生成的代理类对象,代理类直接序列化是有问题的,WCF传输过程是需要序列化的。

1.原本打算用  ProxyDataContractResolver的,设置好了,在WPF(.net framework 4.5)中能够获取到,但是在Unity中(Unity2017.3)有问题:
ArgumentException: failed to convert parameters
System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Reflection/MonoMethod.cs:192)
System.Reflection.MonoProperty.SetValue (System.Object obj, System.Object value, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] index, System.Globalization.CultureInfo culture) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Reflection/MonoProperty.cs:331)
System.Reflection.PropertyInfo.SetValue (System.Object obj, System.Object value, System.Object[] index) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Reflection/PropertyInfo.cs:102)
System.Runtime.Serialization.SerializationMap.SetValue (System.Runtime.Serialization.DataMemberInfo dmi, System.Object obj, System.Object value)
Rethrow as InvalidOperationException: Failed to set value of type System.Collections.ArrayList for property Location.WCFServiceReferences.LocationServices.Area[] Areas
System.Runtime.Serialization.SerializationMap.SetValue (System.Runtime.Serialization.DataMemberInfo dmi, System.Object obj, System.Object value)
System.Runtime.Serialization.SerializationMap.DeserializeContent (System.Xml.XmlReader reader, System.Runtime.Serialization.XmlFormatterDeserializer deserializer, Boolean empty)
System.Runtime.Serialization.SerializationMap.DeserializeContent (System.Xml.XmlReader reader, System.Runtime.Serialization.XmlFormatterDeserializer deserializer)
System.Runtime.Serialization.SerializationMap.DeserializeObject (System.Xml.XmlReader reader, System.Runtime.Serialization.XmlFormatterDeserializer deserializer)
System.Runtime.Serialization.XmlFormatterDeserializer.DeserializeByMap (System.Xml.XmlQualifiedName name, System.Type type, System.Xml.XmlReader reader)
System.Runtime.Serialization.XmlFormatterDeserializer.DeserializeCore (System.Type type, System.Xml.XmlReader reader)
System.Runtime.Serialization.XmlFormatterDeserializer.Deserialize (System.Type type, System.Xml.XmlReader reader)
System.Runtime.Serialization.CollectionTypeMap.DeserializeContent (System.Xml.XmlReader reader, System.Runtime.Serialization.XmlFormatterDeserializer deserializer)
System.Runtime.Serialization.SerializationMap.DeserializeObject (System.Xml.XmlReader reader, System.Runtime.Serialization.XmlFormatterDeserializer deserializer)
System.Runtime.Serialization.XmlFormatterDeserializer.DeserializeByMap (System.Xml.XmlQualifiedName name, System.Type type, System.Xml.XmlReader reader)
System.Runtime.Serialization.XmlFormatterDeserializer.DeserializeCore (System.Type type, System.Xml.XmlReader reader)
System.Runtime.Serialization.XmlFormatterDeserializer.Deserialize (System.Type type, System.Xml.XmlReader reader)
System.Runtime.Serialization.XmlFormatterDeserializer.Deserialize (System.Xml.XmlReader reader, System.Type type, System.Runtime.Serialization.KnownTypeCollection knownTypes, IDataContractSurrogate surrogate, System.String name, System.String ns, Boolean verifyObjectName)
System.Runtime.Serialization.DataContractSerializer.ReadObject (System.Xml.XmlDictionaryReader reader, Boolean verifyObjectName)
System.Runtime.Serialization.XmlObjectSerializer.ReadObject (System.Xml.XmlDictionaryReader reader)
System.ServiceModel.Dispatcher.DataContractMessagesFormatter.MessageToParts (System.ServiceModel.Description.MessageDescription md, System.ServiceModel.Channels.Message message)
System.ServiceModel.Dispatcher.BaseMessagesFormatter.DeserializeReply (System.ServiceModel.Channels.Message message, System.Object[] parameters)
System.ServiceModel.ClientRuntimeChannel.Request (System.ServiceModel.Description.OperationDescription od, System.Object[] parameters)
System.ServiceModel.ClientRuntimeChannel.DoProcess (System.Reflection.MethodBase method, System.String operationName, System.Object[] parameters)
System.ServiceModel.ClientRuntimeChannel.Process (System.Reflection.MethodBase method, System.String operationName, System.Object[] parameters)

怀疑是Unity中的System.ServiceModel的版本(3.0)和WCF服务那边的版本(4.0)不同导致的,WPF做客户端时版本是相同的。

总之new 出来的对象是能传输的,EF查询出来的代理类对象是不能传输的,就算使用 ProxyDataContractResolver,在Unity中也是不行的。
2.采用反射克隆的方式,但是我之前写的函数只能浅克隆,子节点没有克隆进去。
3.采用DataContractSerializer的方式进行克隆,要设置DataContract和DataMember。
Department定位变成
 /// <summary>
    /// 机构
    /// </summary>
    [DataContract]
    public class Department : ITreeNode<Department>, IDepartment
    {
        [DataMember]
        public int Id { get; set; }

        [DataMember]
        [Display(Name="机构名")]
        public string Name { get; set; }

        [DataMember]
        [Display(Name = "排序")]
        public int ShowOrder { get; set; }

        [XmlIgnore]
        [Display(Name = "上级机构")]
        public virtual Department Parent { get; set; }

        [DataMember]
        public int? ParentId { get; set; }

        [DataMember]
        [ForeignKey("ParentId")]
        public virtual List<Department> Children { get; set; }
    }
从数据库中获取根节点,传给Unity,有问题
        public Department GetDepartmentRoot()
        {
            try
            {
                Department dep1 = db.Departments.GetRoot();
                Department dep2 = dep1.CloneObject();
                return dep2;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
                return null;
            }
       }
        public static T CloneObject<T>(this T obj) where T : class,new()
        {
            return CloneByDataContract(obj);
        }
        public static T CloneByDataContract<T>(this T obj)
        {
            var serializer = new DataContractSerializer(typeof(T), new DataContractSerializerSettings()
            {
                DataContractResolver = new ProxyDataContractResolver()
            });
            using (var stream = new MemoryStream())
            {
                // 反序列化
                serializer.WriteObject(stream, obj);
                stream.Seek(0, SeekOrigin.Begin);
                T objNew = (T)serializer.ReadObject(stream);
                return objNew;
            }
        }
ArgumentException: failed to convert parameters
System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Reflection/MonoMethod.cs:192)
System.Reflection.MonoProperty.SetValue (System.Object obj, System.Object value, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] index, System.Globalization.CultureInfo culture) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Reflection/MonoProperty.cs:331)
System.Reflection.PropertyInfo.SetValue (System.Object obj, System.Object value, System.Object[] index) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Reflection/PropertyInfo.cs:102)
System.Runtime.Serialization.SerializationMap.SetValue (System.Runtime.Serialization.DataMemberInfo dmi, System.Object obj, System.Object value)
Rethrow as InvalidOperationException: Failed to set value of type System.Collections.ArrayList for property Location.WCFServiceReferences.LocationServices.Department[] Children
System.Runtime.Serialization.SerializationMap.SetValue (System.Runtime.Serialization.DataMemberInfo dmi, System.Object obj, System.Object value)
System.Runtime.Serialization.SerializationMap.DeserializeContent (System.Xml.XmlReader reader, System.Runtime.Serialization.XmlFormatterDeserializer deserializer, Boolean empty)
System.Runtime.Serialization.SerializationMap.DeserializeContent (System.Xml.XmlReader reader, System.Runtime.Serialization.XmlFormatterDeserializer deserializer)
System.Runtime.Serialization.SerializationMap.DeserializeObject (System.Xml.XmlReader reader, System.Runtime.Serialization.XmlFormatterDeserializer deserializer)
System.Runtime.Serialization.XmlFormatterDeserializer.DeserializeByMap (System.Xml.XmlQualifiedName name, System.Type type, System.Xml.XmlReader reader)
System.Runtime.Serialization.XmlFormatterDeserializer.DeserializeCore (System.Type type, System.Xml.XmlReader reader)
System.Runtime.Serialization.XmlFormatterDeserializer.Deserialize (System.Type type, System.Xml.XmlReader reader)
System.Runtime.Serialization.CollectionTypeMap.DeserializeContent (System.Xml.XmlReader reader, System.Runtime.Serialization.XmlFormatterDeserializer deserializer)
System.Runtime.Serialization.SerializationMap.DeserializeObject (System.Xml.XmlReader reader, System.Runtime.Serialization.XmlFormatterDeserializer deserializer)
System.Runtime.Serialization.XmlFormatterDeserializer.DeserializeByMap (System.Xml.XmlQualifiedName name, System.Type type, System.Xml.XmlReader reader)
System.Runtime.Serialization.XmlFormatterDeserializer.DeserializeCore (System.Type type, System.Xml.XmlReader reader)
System.Runtime.Serialization.XmlFormatterDeserializer.Deserialize (System.Type type, System.Xml.XmlReader reader)
System.Runtime.Serialization.SerializationMap.DeserializeContent (System.Xml.XmlReader reader, System.Runtime.Serialization.XmlFormatterDeserializer deserializer, Boolean empty)
System.Runtime.Serialization.SerializationMap.DeserializeContent (System.Xml.XmlReader reader, System.Runtime.Serialization.XmlFormatterDeserializer deserializer)
System.Runtime.Serialization.SerializationMap.DeserializeObject (System.Xml.XmlReader reader, System.Runtime.Serialization.XmlFormatterDeserializer deserializer)
System.Runtime.Serialization.XmlFormatterDeserializer.DeserializeByMap (System.Xml.XmlQualifiedName name, System.Type type, System.Xml.XmlReader reader)
System.Runtime.Serialization.XmlFormatterDeserializer.DeserializeCore (System.Type type, System.Xml.XmlReader reader)
System.Runtime.Serialization.XmlFormatterDeserializer.Deserialize (System.Type type, System.Xml.XmlReader reader)
System.Runtime.Serialization.CollectionTypeMap.DeserializeContent (System.Xml.XmlReader reader, System.Runtime.Serialization.XmlFormatterDeserializer deserializer)
System.Runtime.Serialization.SerializationMap.DeserializeObject (System.Xml.XmlReader reader, System.Runtime.Serialization.XmlFormatterDeserializer deserializer)
System.Runtime.Serialization.XmlFormatterDeserializer.DeserializeByMap (System.Xml.XmlQualifiedName name, System.Type type, System.Xml.XmlReader reader)
System.Runtime.Serialization.XmlFormatterDeserializer.DeserializeCore (System.Type type, System.Xml.XmlReader reader)
System.Runtime.Serialization.XmlFormatterDeserializer.Deserialize (System.Type type, System.Xml.XmlReader reader)
System.Runtime.Serialization.SerializationMap.DeserializeContent (System.Xml.XmlReader reader, System.Runtime.Serialization.XmlFormatterDeserializer deserializer, Boolean empty)
System.Runtime.Serialization.SerializationMap.DeserializeContent (System.Xml.XmlReader reader, System.Runtime.Serialization.XmlFormatterDeserializer deserializer)
System.Runtime.Serialization.SerializationMap.DeserializeObject (System.Xml.XmlReader reader, System.Runtime.Serialization.XmlFormatterDeserializer deserializer)
System.Runtime.Serialization.XmlFormatterDeserializer.DeserializeByMap (System.Xml.XmlQualifiedName name, System.Type type, System.Xml.XmlReader reader)
System.Runtime.Serialization.XmlFormatterDeserializer.DeserializeCore (System.Type type, System.Xml.XmlReader reader)
System.Runtime.Serialization.XmlFormatterDeserializer.Deserialize (System.Type type, System.Xml.XmlReader reader)
System.Runtime.Serialization.XmlFormatterDeserializer.Deserialize (System.Xml.XmlReader reader, System.Type type, System.Runtime.Serialization.KnownTypeCollection knownTypes, IDataContractSurrogate surrogate, System.String name, System.String ns, Boolean verifyObjectName)
System.Runtime.Serialization.DataContractSerializer.ReadObject (System.Xml.XmlDictionaryReader reader, Boolean verifyObjectName)
System.Runtime.Serialization.XmlObjectSerializer.ReadObject (System.Xml.XmlDictionaryReader reader)
System.ServiceModel.Dispatcher.DataContractMessagesFormatter.MessageToParts (System.ServiceModel.Description.MessageDescription md, System.ServiceModel.Channels.Message message)
System.ServiceModel.Dispatcher.BaseMessagesFormatter.DeserializeReply (System.ServiceModel.Channels.Message message, System.Object[] parameters)
System.ServiceModel.ClientRuntimeChannel.Request (System.ServiceModel.Description.OperationDescription od, System.Object[] parameters)
System.ServiceModel.ClientRuntimeChannel.DoProcess (System.Reflection.MethodBase method, System.String operationName, System.Object[] parameters)
System.ServiceModel.ClientRuntimeChannel.Process (System.Reflection.MethodBase method, System.String operationName, System.Object[] parameters)

Children上面的DataMember去掉,就没问题了。

但是new出来的对象就没问题
        public Department GetDepartmentRoot()
        {
            try
            {
                Department dep3 = new Department() { Id = 1, Name = "Root1" };
                Department dep4 = new Department() { Id= 2,Name = "Child1", ParentId = 1 };
                dep3.Children = new List<Department>();
                dep3.Children.Add(dep4);

                Department dep5 = new Department() { Name = "Child112", ParentId = 2 };
                dep4.Children = new List<Department>();
                dep4.Children.Add(dep5);

                string xml3 = dep3.GetXmlText();
                return dep3;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
                return null;
            }
        }

如果是不能传递Children的话,应该都不行的,也就是不是类结构的问题。
经过实验,发现是Children为数量空就不行,null可以,有子节点也可以。
        public Department GetDepartmentRoot()
        {
            try
            {
                IList<Department> deps = db.Departments.ToList();
                foreach (Department dep in deps)
                {
                    if (dep.Children.Count == 0)
                    {
                        dep.Children = null;
                    }
                }
                return deps[0];
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
                return null;
            }
        }
这样就行了。
突然发现,奇怪, 不用Clone传输的对象也没问题啊
是DataContract属性加的的关系吗?
试了试没加DataContract属性,也可以传输。
代理类没有禁用,GetType()类型确实是代理类。

注释掉服务宿主的 host.SetProxyDataContractResolver();
不行,那就是 ProxyDataContractResolver起作用了,但是一开始确实有问题,一开始时我是所有的EF类都没有加上DataContract...难道一个加上了就其作用了?
奇怪。这个先放着,总之不用每个服务代码中都加上Clone了。
继续Children的实验。
因为客户端这边的Children是数组,考虑将服务端也改成数组,结果所有的Department的Children都是null了,EF中关联表的集合对象只能用List,IList吗?
暂时先用Children=null处理吧,现在我对于EF和WCF的知识都还不够,后续有了新知识后再改。
搜索
Rethrow as InvalidOperationException: Failed to set value of type System.Collections.ArrayList for property Location.WCFServiceReferences.LocationServices.Department[] Children
https://answers.unity.com/questions/270072/failure-to-convert-parameter-when-serializing.html
这个的问题和我的一样,然后他的处理方式也是不传Empty,传null。

今天比较晚了,后续再研究吧。
--------------------------------------------------------

回头一看第一点,根本和版本无关,就是空数组的问题Failed to set value of type System.Collections.ArrayList

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值