Silverlight WCF:将派生对象的集合作为基类的集合使用会导致 NetDispatcherFaultException
Posted
技术标签:
【中文标题】Silverlight WCF:将派生对象的集合作为基类的集合使用会导致 NetDispatcherFaultException【英文标题】:Silverlight WCF: consuming a collection of derived objects as a collection of base class results in a NetDispatcherFaultException 【发布时间】:2015-11-12 18:21:03 【问题描述】:-
以下是 Silverlight 中的已知错误吗?
如果是这样,有什么好的解决方法吗?
类层次结构很简单:
在第一个 PCL 上:
namespace ClassLibrary1
[DataContract]
public class BaseClass
[DataMember]
public string BaseString get; set;
在第二个 PCL 上(当然,引用第一个...)
namespace ClassLibrary2
[DataContract]
public class Derived : BaseClass
[DataMember]
public string DerivedString get; set;
服务(在 WebApp 上):
namespace SilverlightApplication1.Web
[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[KnownType(typeof(Derived))]
public class Service1
[OperationContract]
public List<BaseClass> GetSomething()
var data = new List<BaseClass>();
data.Add(new Derived());
return data;
现在, 服务引用不会将 ServiceKnownType 属性添加到 reference.cs 文件。以及由此产生的错误:
格式化程序在尝试反序列化消息时抛出异常:尝试反序列化参数时出错:GetQueueItemsResult。 InnerException 消息是'元素'http://schemas.datacontract.org/2004/07/XXX_BASE_CLASS'包含'http://schemas.datacontract.org/2004/07/XXX_DERIVED_CLASS'数据协定的数据。反序列化器不知道映射到该合约的任何类型。将与 'DERIVED_CLASS' 对应的类型添加到已知类型列表中 - 例如,通过使用 KnownTypeAttribute 属性或将其添加到传递给 DataContractSerializer 的已知类型列表中。有关详细信息,请参阅 InnerException。
[更新] 当然,错误是在客户端上抛出的。服务器端返回正确的值,但客户端无法正确解析它们。 Fiddler 说服务器返回了 0 个字节。 但实际上是客户未能反序列化数据。
我需要一些方法来告诉运行时反序列化器如何将 BaseClass 反序列化为实际传输的类型。 [/更新]
【问题讨论】:
【参考方案1】:您需要告诉 DataContractSerializer 将派生的序列化为基类。为此,您需要使用派生类上的 Name 属性来阐明 DataContract:
[DataContract(Name="BaseClass")]
public class Derived : BaseClass
[DataMember]
public string DerivedString get; set;
我 100% 不确定您是否需要将 Derived
声明为 KnownType
- 我强烈怀疑您这样做。
此外,您在 Service 类上使用 KnownType - 据我了解,您应该在此处使用 ServiceKnownType。通常您可以选择: 一种。在对象类上使用 KnownType。 湾。在服务合同上使用 ServiceKnownType(通常在服务的接口声明上)。 我更喜欢后面的b。因为它将所有 KnownTypes 分组在一个地方 - where as a.让它们分散在每个对象的代码中 - 但这只是个人喜好。
【讨论】:
序列化似乎没问题。是反序列化失败...查看对问题的编辑 以上假设客户端只需要 Base 对象。如果您想要 Derived 对象客户端,则只需序列化为 Derived 但不要将任何 [DataMemeber] 添加到 Derived(即所有状态都在 Base 中)。实际上,它将仅序列化基本部分,但反序列化为 Derived。 是的,我想我在传输它时并不清楚:(【参考方案2】:如何在DataContract
类型定义中设置KnownType属性,让反序列化器在运行时找到正确的类型,是否解决问题?
namespace ClassLibrary1
[DataContract]
[KnownType(typeof(BaseClass))]
[KnownType(typeof(Derived))]
public class BaseClass
[DataMember]
public string BaseString get; set;
namespace ClassLibrary2
[DataContract]
[KnownType(typeof(BaseClass))]
[KnownType(typeof(Derived))]
public class Derived : BaseClass
[DataMember]
public string DerivedString get; set;
老实说,我不确定您是否必须在两个 DataContracts 上设置属性,或者仅在派生类型或仅在基类型上设置属性。
【讨论】:
仅此而已。他实际上需要告诉 DataContractResolve 使用什么契约——即使用派生类的基类契约。 @Ricibob 基本上是正确的。当然我不能在基类上使用 KnownType 属性(愚蠢的 MS 认为这是一个正常的场景不是吗?)【参考方案3】:这似乎是 Silverlight/客户端代码生成器中的一个错误。
如果您的服务返回“基类”集合,silverlight 客户端代码生成器(添加服务引用)将无法将派生类型添加为 ServiceKnownType / KnowType 或生成的客户端代码上的任何内容。
我们目前使用的解决方案(直到我们完全放弃 SL)是手动将 ServiceKnownType 声明复制粘贴到所有派生类型的生成代码中 - 每次我们生成代码时。
恶心!但有效。
【讨论】:
以上是关于Silverlight WCF:将派生对象的集合作为基类的集合使用会导致 NetDispatcherFaultException的主要内容,如果未能解决你的问题,请参考以下文章
我是不是必须使用 WCF 对 silverlight 应用程序中的对象进行序列化/反序列化?