【问题标题】:WCF Disable Deserialization Order SensitivityWCF 禁用反序列化顺序敏感性
【发布时间】:2010-12-16 04:59:46
【问题描述】:

在非 .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 会将错误定位的元素视为 null。

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

所以,我的问题是:你能告诉 WCF 反序列化器在反序列化对象时忽略字段的顺序吗?

【问题讨论】:

    标签: .net wcf serialization


    【解决方案1】:

    您可以通过装饰数据协定中的元素来指定序列化顺序:

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

    因此您可以确保序列化顺序始终相同。但是没有办法告诉反序列化器“忘记”订单 - 关键是:这是通过 XML 模式处理的,并使用 &lt;xs:sequence&gt; 元素完成 - 这确实暗示并需要订单。恐怕你不能把它关掉。

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

    【讨论】:

    • 啊,感谢您提供有关&lt;xs:sequence&gt; 的信息。我没有深入研究正在生成的架构定义。
    【解决方案2】:

    您可以使用 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

    【讨论】:

    • 谢谢 - 问题是,有时缺少元素是有效的。 Ohwell - IsRequired 可能是我可以做到的更简单的解决方案。
    【解决方案3】:

    这里有一个旧线程:

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

    看起来唯一的选择是交换序列化程序,但后来它变成了选择加入,这更烦人。

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

    【讨论】:

    • 有趣。现在只需编写一个获取消息的拦截器,询问 WCF 方法以确定预期的类型,使用 XmlSerializer 反序列化(根据线程确实有效),并使用 DataContractSerializer 重新序列化。多么简单;)仍然……可能是唯一可以按预期实际工作的解决方案。谢谢:)
    • @WillHughes - 我很好奇你是如何实现上述想法的?
    • 有趣。我有相反的问题。我有一个 WCF 生成的客户端代理,它具有基于服务器 WSDL 中的序列的 Order=x 属性,但返回的数据通常会遗漏空/空字段(错误地)。无论如何,这在生成的代理中都会失败。为了完成这项工作,我从生成的代理中明确删除了 Order= 属性,现在反序列化可以正常工作。因此,只要合约没有 Order= 属性,DCS 似乎确实可以理解乱序结果。这是在 .NET 4.0 上 - 因为这个线程是旧的,所以可能已经改变了。
    • 这是一个很好的资源。我有一种情况,我无法控制正在生成的服务(并且订单可以在其中更改)。如果我删除 Reference.cs 中的“全部”Order 属性值,我会得到所有值 deserailized :) 想知道是否有任何工具可以删除 reference.cs 中的 OrderBy
    • 我们能够删除 Reference.cs 中属性的 Order 属性值,以使反序列化器忽略序列,例如 Looneystar。
    【解决方案4】:

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

    当引用一个旧的 asmx Web 服务时,我们在服务器 wsdl 中“插入”新字段“之后”的所有字段都有空值。 因此,每当在服务器端添加新字段时,都会在客户端取消几个值。这迫使我们更新代码中的引用以始终坚持使用服务器 wsdl。

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-02-24
      • 2012-03-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-29
      • 1970-01-01
      相关资源
      最近更新 更多