2013-10-21 116 views
7

我有以下的ServiceContract和DataContract类:WCF列表<string >序列化/反序列化错误

[ServiceContract] 
public interface IWcfService 
{ 
    [OperationContract] 
    Response GetData(); 
} 

[DataContract] 
public class Response 
{ 
    [DataMember] 
    public Dictionary<string, object> Data { get; set; } 
} 

当Response.Data字典的值的类型是int,字符串,双或任何其他“简单”的基本类型的,WCF可以成功地序列化对象。但是,当Response.Data字典的值类型列表<字符串>的,itreceived数据,并试图反序列化时,客户端抛出以下异常:

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等。它将通过使用Dictionary来帮助解决这个问题,但它也会丢失原始类型信息。例如,客户端需要List并执行一些数据绑定来显示集合,因此在这种情况下List.ToString()将不会有帮助。

+2

据推测在字典中的值中的一个是'串[]'或'列表'?我不得不说:在数据合同中的任何一点使用'object' ***应立即引发警钟。 'object' *不是合同* - 合同是全部*不存在*。然而!您是否尝试过包括'[KnownType(typeof(string []))]'/'[ServiceKnownType(typeof(string []))](注意:添加随机属性并不是解决问题的最佳方式) –

+0

字典中的值是列表,它会导致问题。我也尝试使用[KnownType(typeof(string []))]/[ServiceKnownType(typeof(string []))],但它没有帮助 – wd113

+0

您是否使用Add Service Reference创建调用客户端服务? –

回答

1

感谢大家的意见。我设法通过配置WCF使用NetDataContractSerializer作为序列化程序(默认为DataContractSerializer)来解决问题。 NetDataContractSerializer在序列化时会包含更多的CLR类型信息,尽管它具有性能优势(大约是序列化时间的两倍)。

+0

感谢您的提示!我用它来解决我长期存在的问题,即如何从客户端向服务器发送异常以进行日志记录。这是我做[做](http://stackoverflow.com/a/28737527/722393)。再次感谢。 – InteXX

1

记住,你的数据合同引起的过线序列化到字符串,所以任何对象,你传递over必须是可序列化的(其中object不是)。

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

这个问题是由于WCF非常擅长抽象化服务的底层渠道,所以您很想忘记您现在正在“面向服务”的环境中工作(KnownTypes是一个黑客攻击面向对象的错觉)。数据合同构成了您的服务的“公共”API的一部分,因此必须明确表示您的服务所暴露的数据。拥有返回“动态”数据的数据结构违反了这一重要规则。

客户端需要知道它是得到什么数据备份,所以如果你想实现一个“动态”的回应,你应该在响应中的变化实现(比方说)不同的方法/终端/服务。在您的服务中,没有理由不能使用多态来简化代码 - 但这不应该泄漏到公共服务/数据合约中。