类层次结构很简单:
第一个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消息是&#39;元素&#39; http://schemas.datacontract.org/2004/07/XXX_BASE_CLASS&#39;包含&#39; http://schemas.datacontract.org/2004/07/XXX_DERIVED_CLASS&#39;的数据。数据合同。反序列化器不知道映射到此合同的任何类型。添加与&#39; DERIVED_CLASS&#39;对应的类型到已知类型列表 - 例如,通过使用KnownTypeAttribute属性或将其添加到传递给DataContractSerializer的已知类型列表。&#39;。有关详细信息,请参阅InnerException。
[增订] 当然,错误是在客户端上引发的。服务器端返回正确的值,客户端无法正确解析它们。 Fiddler说服务器返回0字节。 但实际上,客户端无法反序列化数据。
我需要一些方法告诉运行时反序列化器如何将BaseClass反序列化为实际传输的类型。 [/更新]
答案 0 :(得分: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分组在一个地方 - 作为一个地方。让他们在每个对象的代码上进行搜索 - 但这只是个人偏好。
答案 1 :(得分:0)
如何在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上设置属性还是仅在派生类型中设置属性,或仅在basetype上设置属性。
答案 2 :(得分:0)
这似乎是Silverlight /客户端代码生成器中的一个错误。
如果你有一个服务返回&#34;基类&#34; silverlight客户端代码生成器(添加服务引用)将无法将派生类型添加为ServiceKnownType / KnowType或生成的客户端代码上的任何内容。
我们当前使用的解决方案(直到我们完全放弃SL)是每次生成代码时,手动将ServiceKnownType声明复制粘贴到所有派生类型的生成代码中。
恶心!但是有效。