简体   繁体   English

Silverlight WCF:将派生对象的集合用作基类的集合会导致NetDispatcherFaultException

[英]Silverlight WCF: consuming a collection of derived objects as a collection of base class results in a NetDispatcherFaultException

  1. is the following a known bug in Silverlight? 以下是Silverlight中的已知错误吗?
  2. if so, are there any good workarounds? 如果是这样,是否有任何好的解决方法?

the class hierarchy is simple: 类的层次结构很简单:

on the first PCL: 在第一个PCL上:

namespace ClassLibrary1
{
    [DataContract]
    public class BaseClass
    {
        [DataMember]
        public string BaseString { get; set; }
    }
}

on the second PCL (of course, referencing the first...) 在第二个PCL上(当然,引用第一个...)

namespace ClassLibrary2
{
    [DataContract]
    public class Derived : BaseClass
    {
        [DataMember]
        public string DerivedString { get; set; }
    }
}

the service (on the WebApp): 服务(在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;
        }

    }
}

Now, the service reference does not add the ServiceKnownType attribute to the reference.cs file. 现在,服务引用不会将ServiceKnownType属性添加到reference.cs文件。 and the resulting error: 和产生的错误:

The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter :GetQueueItemsResult. 格式化程序尝试反序列化消息时引发异常:尝试反序列化参数:GetQueueItemsResult时发生错误。 The InnerException message was 'Element ' http://schemas.datacontract.org/2004/07/XXX_BASE_CLASS ' contains data of the ' http://schemas.datacontract.org/2004/07/XXX_DERIVED_CLASS ' data contract. InnerException消息是“元素” http://schemas.datacontract.org/2004/07/XXX_BASE_CLASS ,其中包含“ http://schemas.datacontract.org/2004/07/XXX_DERIVED_CLASS ”数据协定的数据。 The deserializer has no knowledge of any type that maps to this contract. 解串器不知道任何映射到该合同的类型。 Add the type corresponding to 'DERIVED_CLASS' to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding it to the list of known types passed to DataContractSerializer.'. 将与“ DERIVED_CLASS”相对应的类型添加到已知类型的列表中-例如,通过使用KnownTypeAttribute属性或将其添加到传递给DataContractSerializer的已知类型的列表中。 Please see InnerException for more details. 有关更多详细信息,请参见InnerException。

[UPDATED] the error is thrown on the client, of course. [更新]当然会在客户端引发错误。 the server side returns the correct values, bu the client cannot parse them properly. 服务器端会返回正确的值,但客户端无法正确解析它们。 Fiddler says the server returned 0 bytes. Fiddler说服务器返回了0个字节。 but in reality it's the client who fails to deserialize the data. 但实际上是客户无法反序列化数据。

I need some way to tell the runtime deserializer how to deserialize the BaseClass into the actual type transferred. 我需要一些方法来告诉运行时反序列化器如何将BaseClass反序列化为实际传输的类型。 [/UPDATED] [/更新]

You need to tell the DataContractSerializer to serialize the derived as the base class. 您需要告诉DataContractSerializer将序列化的序列化为基类。 To do this you need to clarify the DataContract with a Name attribute on the derived class: 为此,您需要在派生类上使用Name属性来阐明DataContract:

[DataContract(Name="BaseClass")]
public class Derived : BaseClass 
    [DataMember]
    public string DerivedString { get; set; }
}

Im 100% not sure if you need to declare the Derived as a KnownType - I suspect strongly that you DO. 我100%不确定是否需要将Derived声明为KnownType我强烈怀疑您这样做。

In addition you are using KnownType on the Service class - its my understanding you should use ServiceKnownType here. 另外,您正在Service类上使用KnownType-就我的理解,您应该在此处使用ServiceKnownType。 Generally you have a choice either: 通常,您可以选择:
a. 一种。 Use KnownType on the object classes. 在对象类上使用KnownType。
b. b。 Use ServiceKnownType on the Service contract (usually on the Interface delcaration for the Service). 在服务合同上使用ServiceKnownType(通常在服务的接口代理上)。
I prefer the later b. 我喜欢后来的b。 because it groups all KnownTypes in one place - where as a. 因为它将所有KnownTypes集中在一个地方-一个。 has them scatered all over the code on each object - but that is just personal prefernce. 让他们在每个对象的所有代码中进行分类-但这只是个人喜好。

How about setting the KnownType attributes at the DataContract type definitions, enabling the deserializer to find the correct type during runtime, does it solve the issue? 如何在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; }
    }
}

To be honest, I'm not sure whether you have to set the attributes at both DataContracts or only at the derived type or only at the basetype. 老实说,我不确定您是否必须在两个DataContracts上设置属性,还是只在派生类型上设置属性,还是在基类型上设置属性。

This seems to be a bug in Silverlight/client code generator. 这似乎是Silverlight /客户端代码生成器中的错误。

if you have a service returning a collection of "base class" the silverlight client code generator (add service reference) will not be able to add the derived types as ServiceKnownType / KnowType or whatever on the generated client code. 如果您有返回“基类”集合的服务,silverlight客户端代码生成器(添加服务引用)将无法将派生类型添加为ServiceKnownType / KnowType或在生成的客户端代码上添加任何内容。

the solution we are currently using (until we abandon SL altogether) is to manually copy-paste the ServiceKnownType declarations into the generated code for all derived type - every time we generate the code. 我们当前使用的解决方案(直到我们完全放弃SL)是将ServiceKnownType声明手动复制粘贴到所有派生类型的生成代码中-每次生成代码时。

disgusting! 真恶心! but works. 但是有效。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM