Silverlight WCF:将派生对象的集合作为基础 class 的集合使用会导致 NetDispatcherFaultException
Silverlight WCF: consuming a collection of derived objects as a collection of base class results in a NetDispatcherFaultException
- 以下是 Silverlight 中的已知错误吗?
- 如果是这样,有什么好的解决方法吗?
class 层次结构很简单:
第一个 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 文件。以及由此产生的错误:
The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter :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. 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.'. Please see InnerException for more details.
[更新]
当然,错误是在客户端抛出的。服务器端 returns 正确的值,但客户端无法正确解析它们。
Fiddler 说服务器返回了 0 个字节。
但实际上是客户端未能反序列化数据。
我需要一些方法来告诉运行时反序列化程序如何将 BaseClass 反序列化为实际传输的类型。
[/更新]
如何在 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 上设置属性,还是只在派生类型或基类型上设置属性。
您需要告诉 DataContractSerializer 将派生序列化为基 class。为此,您需要在派生的 class:
上使用 Name 属性阐明 DataContract
[DataContract(Name="BaseClass")]
public class Derived : BaseClass
[DataMember]
public string DerivedString { get; set; }
}
我 100% 不确定您是否需要将 Derived
声明为 KnownType
- 我强烈怀疑您需要声明。
此外,您还在服务上使用 KnownType class - 据我了解,您应该在此处使用 ServiceKnownType。通常您可以选择:
一种。在对象上使用 KnownType classes.
b.在服务契约上使用 ServiceKnownType(通常在服务的接口声明上)。
我更喜欢后面的b。因为它将所有 KnownTypes 分组在一个地方 - 其中作为 a.让它们分散在每个对象的代码中 - 但这只是个人偏好。
这似乎是 Silverlight/client 代码生成器中的错误。
如果您有返回 "base class" 集合的服务,则 silverlight 客户端代码生成器(添加服务引用)将无法将派生类型添加为 ServiceKnownType / KnowType 或生成的客户端代码中的任何内容。
我们目前使用的解决方案(直到我们完全放弃 SL)是手动将 ServiceKnownType 声明复制粘贴到所有派生类型的生成代码中 - 每次我们生成代码时。
恶心!但有效。
- 以下是 Silverlight 中的已知错误吗?
- 如果是这样,有什么好的解决方法吗?
class 层次结构很简单:
第一个 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 文件。以及由此产生的错误:
The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter :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. 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.'. Please see InnerException for more details.
[更新] 当然,错误是在客户端抛出的。服务器端 returns 正确的值,但客户端无法正确解析它们。 Fiddler 说服务器返回了 0 个字节。 但实际上是客户端未能反序列化数据。
我需要一些方法来告诉运行时反序列化程序如何将 BaseClass 反序列化为实际传输的类型。 [/更新]
如何在 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 上设置属性,还是只在派生类型或基类型上设置属性。
您需要告诉 DataContractSerializer 将派生序列化为基 class。为此,您需要在派生的 class:
上使用 Name 属性阐明 DataContract[DataContract(Name="BaseClass")]
public class Derived : BaseClass
[DataMember]
public string DerivedString { get; set; }
}
我 100% 不确定您是否需要将 Derived
声明为 KnownType
- 我强烈怀疑您需要声明。
此外,您还在服务上使用 KnownType class - 据我了解,您应该在此处使用 ServiceKnownType。通常您可以选择:
一种。在对象上使用 KnownType classes.
b.在服务契约上使用 ServiceKnownType(通常在服务的接口声明上)。
我更喜欢后面的b。因为它将所有 KnownTypes 分组在一个地方 - 其中作为 a.让它们分散在每个对象的代码中 - 但这只是个人偏好。
这似乎是 Silverlight/client 代码生成器中的错误。
如果您有返回 "base class" 集合的服务,则 silverlight 客户端代码生成器(添加服务引用)将无法将派生类型添加为 ServiceKnownType / KnowType 或生成的客户端代码中的任何内容。
我们目前使用的解决方案(直到我们完全放弃 SL)是手动将 ServiceKnownType 声明复制粘贴到所有派生类型的生成代码中 - 每次我们生成代码时。
恶心!但有效。