我们使用WCF和C#为现有的SOAP Web服务构建了一个客户端.最近,Web服务已更新,我们的客户端停止工作.我认为这个问题最好在Yaron Naveh的博客文章-
Interoperability Gotcha: Order of XML Elements中进行解释.
我会借用Yaron的例子来解答我的问题.最初,wsdl看起来像:
<s:element name="root"> <s:complexType> <s:sequence> <s:element name="elem1" type="s:string" /> <s:element name="elem2" type="s:string" /> </s:sequence> </s:complexType> </s:element">
WCF生成的代理使用显式元素排序,如:
[XmlElement(Order=0)] public string Elem1 { ... } [XmlElement(Order=1)] public string Elem2 { ... }
在更新中,向该类型添加了一个新元素,但此元素已添加到序列的中间.
<s:element name="root"> <s:complexType> <s:sequence> <s:element name="elem1" type="s:string" /> <s:element name="NewElement" type="s:string" /> <s:element name="elem2" type="s:string" /> </s:sequence> </s:complexType> </s:element">
我的WCF代理无法反序列化在添加的NewElement之后排序的任何元素.
Web服务提供商希望此更改与旧客户端向后兼容.显然,我的客户是唯一停止工作的客户.
这是WSDL中的重大变化吗?
是否应将新元素添加到序列的末尾以防止破坏现有客户端?那会使这种向后兼容吗?
如果我删除XmlElement属性上的order参数,我的代理会为这样的未来更改做好更充分的准备吗?如果我删除订单,我会放弃什么?
是的,这是他们的WSDL的一个重大变化.你是对的,将新元素添加到序列的末尾将使其向后兼容.
如果他们希望消费者以任何顺序接受元素,他们应该使用< xsd:all>而不是< xsd:sequence>.当他们添加新元素时,它是必需元素,除非他们将minOccurs =’0’属性添加到其模式定义中以使其成为可选元素.
他们还可以通过添加< xsd:any>来使他们的模式更加向前兼容.元素到它们序列的末尾,作为未来元素的占位符.
如果从代理中删除Order,则可能遇到的主要问题是它们是否允许重复序列中具有相同名称的元素:
<s:element name="root"> <s:complexType> <s:sequence> <s:element name="elem1" type="s:string" /> <s:element name="elem2" type="s:string" /> <s:element name="elem1" type="s:string" /> </s:sequence> </s:complexType> </s:element">
如果没有您的订购指示器,WCF将不知道要映射到哪个属性的元素重复.如果他们从.NET或Java等方式生成XML,则这不太可能成为问题,因为这些通常会将数组和列表转换为包含重复子元素的单个父元素.
使用< xsd:all>的另一个好处是因为它不允许重复使用相同名称的元素,从而避免了这个问题. < XSD:序列>具有允许同名的多个元素的“特征”,仅由它们在列表中的位置区分.