在非.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>
注意:属性按字母顺序序列化。
如果您尝试反序列化具有Bar
和ID
位置交换的对象,WCF会将错误定位的元素视为空。
虽然我知道我可以使用DataMember
属性并强制执行特定排序,但我希望减少调试字段“神秘”为空的问题的次数。
所以,我的问题是:在反序列化对象时,是否可以告诉WCF反序列化器忽略字段的顺序。
答案 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流中的新字段: