WCF 列表<字符串>序列化/反序列化错误

本文关键字:反序列化 错误 序列化 列表 字符串 WCF | 更新日期: 2023-09-27 18:36:08

我有以下 ServiceContract 和 DataContract 类:

[ServiceContract] 
public interface IWcfService 
{ 
    [OperationContract] 
    Response GetData(); 
} 
[DataContract]
public class Response 
{ 
    [DataMember] 
    public Dictionary<string, object> Data { get; set; } 
} 

当 Response.Data 字典的值是 int、string、double 或任何其他"简单"基元类型时,WCF 可以成功序列化对象。但是,当 Response.Data 字典的值为 List 类型时,客户端在收到数据并尝试反序列化数据时会引发以下异常:

Message=The formatter threw an exception while trying to deserialize the message: 
There was an error while trying to deserialize parameter http://tempuri.org/:GetDataResult. 
The InnerException message was 'Error in line 1 position 990. 
    Element 'http://schemas.microsoft.com/2003/10/Serialization/Arrays:Value' contains data from a type 
    that maps to the name 'http://schemas.microsoft.com/2003/10/Serialization/Arrays:ArrayOfstring'. 
    The deserializer has no knowledge of any type that maps to this name. 
    Consider using a DataContractResolver or add the type corresponding to 'ArrayOfstring' 
    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.'.

我还尝试将 KnownType 属性添加到 ServiceContract 和 DataContract 中,如下所示:

[ServiceContract] 
[ServiceKnownType(typeof(List<string>))] 
[ServiceKnownType(typeof(Dictionary<string, string>))] 
[ServiceKnownType(typeof(Dictionary<string, List<string>>))] 
public interface IWcfService 
{ 
    [OperationContract] 
    [ServiceKnownType(typeof(List<string>))] 
    [ServiceKnownType(typeof(Dictionary<string, string>))] 
    [ServiceKnownType(typeof(Dictionary<string, List<string>>))] 
    Response GetData(); 
} 
[DataContract] 
[ServiceKnownType(typeof(List<string>))] 
[ServiceKnownType(typeof(Dictionary<string, string>))] 
[ServiceKnownType(typeof(Dictionary<string, List<string>>))] 
[KnownType(typeof(List<string>))] 
[KnownType(typeof(Dictionary<string, string>))] 
[KnownType(typeof(Dictionary<string, List<string>>))] 
public class Response 
{ 
    [DataMember] 
    public Dictionary<string, object> Data { get; set; } 
} 

但这些都无济于事。有人对此有任何想法吗?

更新

数据如下所示:

Data = new new DIctionary<string, object> 
       { 
           {"_id", 12344}, 
           {"names", new List<string>{ "John", "Peter", "Jack"}}, 
           {"time", DateTime.Now} 
       }

我们使用字典的原因<字符串,对象>:服务器需要向客户端发送"动态"数据的字典,可以是int,List,DataTime等。它将通过使用字典来帮助解决此问题,但它也会丢失原始类型信息。例如,客户端需要 List 并执行一些数据绑定来显示集合,因此 List.ToString() 在这种情况下将没有帮助。

WCF 列表<字符串>序列化/反序列化错误

我认为默认情况下System.Object不是Serializable.您需要发送额外信息,但这仍然不是最佳实践,我建议在使用字典之前定义一个单独的类型。

请参阅以下内容:

返回字典数组的 WCF 服务

WCF 系统.对象序列化

在 WCF 中序列化标识

请记住

,您的数据协定通过网络序列化为字符串,因此您传递的任何对象都必须是可序列化的(object不是)。

问题在于您在面向服务的上下文中使用面向对象的模式 - 期望您在字典值中传递的所有内容都是多态的object。 我回答了一个在这里有类似"气味"的问题:https://stackoverflow.com/a/19445875/2382536。

问题归因于这样一个事实,即 WCF 非常擅长抽象出服务的基础通道,您很容易忘记您现在正在"面向服务"上下文中工作(KnownTypes是一个黑客 - 给人一种通过网络进行 OO 的错觉)。 数据协定构成服务的"公共"API 的一部分,因此必须是服务公开的数据的明确显式表示形式。 拥有返回"动态"数据的数据结构违反了这一重要规则。

客户端需要知道它正在返回哪些数据,因此如果要实现"动态"响应,则应为响应中的变体实现(例如)不同的方法/端点/服务。 在你的服务中,没有理由不能使用多态性来简化你的代码 - 但这不应该泄漏到公共服务/数据契约中。

感谢大家的投入。我已经设法通过将 WCF 配置为使用 NetDataContractSerializer 作为序列化程序(默认是 DataContractSerializer)来解决此问题。NetDataContractSerializer 在执行序列化时将包含更多的 CLR 类型信息,尽管它的性能会受到影响(大约是序列化时间的两倍)。