WCF禁用反序列化顺序灵敏度

时间:2009-11-13 07:24:36

标签: .net wcf serialization

在非.NET客户端和.NET WCF服务之间传递序列化对象时,我遇到了一个反复出现的问题。

当WCF反序列化对象时,它严格依赖于属性的顺序。

也就是说,如果我将我的课程定义为:

public class Foo 
{ 
  public int ID { get; set; } 
  public int Bar { get; set; } 
} 

然后WCF会将对象序列化为:

<Foo>
  <Bar>123</Bar>
  <ID>456</ID>
</Foo>

注意:属性按字母顺序序列化。

如果您尝试反序列化具有BarID位置交换的对象,WCF会将错误定位的元素视为空。

虽然我知道我可以使用DataMember属性并强制执行特定排序,但我希望减少调试字段“神秘”为空的问题的次数。

所以,我的问题是:在反序列化对象时,是否可以告诉WCF反序列化器忽略字段的顺序。

4 个答案:

答案 0 :(得分:12)

您可以通过修改数据合同中的元素来指定序列化顺序:

[DataContract]
public class Foo 
{ 
  [DataMember(Order=1)]
  public int ID { get; set; } 

  [DataMember(Order=2)]
  public int Bar { get; set; } 
}

因此,您可以确保序列化顺序始终相同。但是没有办法告诉解串器“忘记”顺序 - 重点是:这是通过XML模式处理的,并使用<xs:sequence>元素完成 - 这确实意味着需要命令。你不能把它关掉,我害怕。

基于该XML架构,您的非.NET客户端应该能够验证他们将要发送的XML是否符合该架构 - 如果不符合,则因为Bar和ID元素具有被交换后,他们不应该发送无效的XML。

答案 1 :(得分:10)

您可以使用DataMember属性的IsRequired属性指定元素是必需的。这样,您将获得更明确的错误消息,表明缺少必需的元素,而不是获得“神秘”的空值。

[DataContract]
public class Foo 
{ 
  [DataMember(IsRequired=true, Order=1)]
  public int ID { get; set; } 

  [DataMember(IsRequired=true, Order=2)]
  public int Bar { get; set; } 
}

您的案例中发生的事情是:

  • DataContract按此顺序需要Bar和ID元素(字母表,因为您没有指定明确的顺序)。

  • 遇到没有前面Bar元素的ID元素。由于Bar不是必需的,它只是忽略它。

  • 将忽略Bar后面的ID元素,因为它处于错误的位置。

话虽如此,将IsRequired设置为true只会对合同的第1版有所帮助。后续版本中添加的元素通常将IsRequired设置为false。 MSDN有an article on data contract versioning

答案 2 :(得分:7)

这里有一个旧线程:

http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/a891928b-d27a-4ef2-83b3-ee407c6b9187

看起来唯一的选择是交换序列化程序,但随后它变成了选择,这更令人讨厌。

编辑:您可以编写自己的序列化程序来重新排序元素,然后将其传递给DataContractSerializer

答案 3 :(得分:0)

对我来说,DataContractSerializer是.NET Framework 4.0的救星

当引用旧的asmx Web服务时,对于在服务器wsdl中“之后”插入新字段的所有字段,我们都具有空值。 因此,无论何时在服务器端添加了新字段,这都会使客户端端的多个值无效。这迫使我们更新代码中的引用,使其始终坚持使用服务器wsdl。

我找到了两种解决方案,以使我们的客户端可以容忍xml流中的新字段:

  • 在Visual Studio中使用旧的网络参考(旧的客户端代码生成器以实现兼容性)
  • 或者使用WCF经典参考,但是在svcmap文件中更改序列化器。 ClientOptions-> Serializer =“ DataContractSerializer”而不是“ Auto”。我发现在我们的例子中,“自动”值与“ XmlSerializer”值相同。