WSDL2.0简介


即使您完全满足于使用成熟的WSDL1.1标准,也值得花时间了解WSDL2.0如何以及为什么改变和扩展了某些特性和语言元素。在本文中,我们开始关注WSDL1.1和2.0之间的差异,然后继续组装一个完整的WSDL2.0文档。注意,本文不是对Web服务描述语言的介绍。如果您是WSDL的新手,请确保在继续之前阅读基本的WSDL1.1元素。

本文作者Kevin Liu并于2009年2月发表在SOA杂志上。

介绍

如图所示,WSDL2.0语言为WSDL定义的文档结构引入了一些明显的差异,即:

定义元素重命名为描述
端口类型元素重命名为接口
港口元素重命名为端点
此外,message元素也被删除,如下一节所述。



 图1:WSDL2.0从WSDL1.1继承了它的整体结构,但确实对抽象和具体描述都做了一些更改。  



消除消息元素

WSDL1.1消息元素主要用作以消息为中心的通信和以RPC为中心的通信之间的桥梁。它可以用来描述一个文档类型消息,仅基于一个零件元素,或者它可以支持基于多个部分的RPC类型(参数驱动)消息。然而,它对于RPC的表达能力是有限的。例如,它不能描述数量可变的输入参数或响应的选择。WSDL2.0通过删除对消息元素。它只允许操作直接引用类型(例如XML模式元素)。



接口定义

WSDL2.0不仅将接口定义的元素名称从端口类型接口,它还扩展了接口使用一组新元素和属性构造,如本例突出显示的部分所示:

<interface name="..." extends="..." styleDefault="...">
<fault name="..." element="..." />
<operation name="..." pattern="..." style="..."
wsdlx:safe="...">
<input messageLabel="..." element="..." />
<output messageLabel="..." element="..." />
<infault ref="..." messageLabel="..." />
<outfault ref="..." messageLabel="..." />
</operation>
</interface>

让我们更近距离地探索这些新元素和属性。


接口元素的扩展属性

面向对象编程引入了接口继承的概念,通过继承并扩展现有接口的操作,可以从现有接口中派生出一个新接口。

可选的扩展属性的接口元素允许一个接口扩展或从一个或多个其他接口继承。在这种情况下,接口包含它扩展的所有操作加上它直接定义的操作。

现在让我们看一个示例,说明扩展属性起作用。

ActionCon引入了一个要求,即任何与采购订单处理相关的活动都必须记录在存储中心中,以便进行审计。如这里所示,Steve定义了一个用于日志记录的接口,然后在几个与采购订单相关的接口之一中使用该接口。

<interface name="ifPurchaseOrderLog">
<operation name="opLogOrder"
pattern="http://www.w3.org/2006/01/wsdl/out-only">
<output messageLabel="Out" element="po:orderLog"/>
</operation>
</interface>

 

IfPurchaseOrderLog接口构造表示可由其他接口构造继承的操作,而ifPurchaseOrder接口构造是通过使用扩展属性。

<interface name="ifPurchaseOrder" extends="tns:ifPurchaseOrderLog" >
<operation name="opChangeOrder"
pattern="http://www.w3.org/2006/01/wsdl/in-out">
<input messageLabel="In" element="po:purchaseOrder "/>
<output messageLabel="Out" element="po:acknowledgement"/>
</operation>
<operation name="opCancelOrder"
pattern="http://www.w3.org/2006/01/wsdl/in-out">
<input messageLabel="In" element="po:poNumber"/>
<output messageLabel="Out" element="po:acknowledgement"/>
</operation>
</interface>

 

作为继承的结果,接口IFPurchaseOrder现在包含三个操作:opLogOrder,opChangeOrder和opCancelOrder。




接口元素的样式默认属性

样式定义应用于操作的某些规则。这个样式默认属性设置的默认值风格接口下所有操作的属性。

<interface name="ifPurchaseOrderLog"
styleDefault="http://www.w3.org/ns/wsdl/style/iri">
<operation name="opLogOrder"
pattern="http://www.w3.org/2006/01/wsdl/out-only">
<output messageLabel="Out" element="po:orderLog"/>
</operation>
</interface>

提供了以下预定义样式值:

RPC样式(http://www.w3.org/ns/wsdl/style/rpc)
要求接口内的所有操作必须遵循RPC样式消息的规则。
虹膜样式(http://www.w3.org/ns/wsdl/style/iri)
对消息定义进行限制,以便可以将它们序列化为类似HTTP URL编码的内容。
多部分(http://www.w3.org/ns/wsdl/style/multipart)
在HTTP绑定中,对于XForms客户机,必须按照这种样式定义消息,并将其序列化为“multipart/form-data”。


WSDL2.0规范中记录了每种样式的确切规则和限制。操作元素可以具有单独的风格属性设置,重写样式默认父级设置接口元素。

样式默认属性是可选的;如果缺少它,这仅仅意味着不需要遵守额外的规则。



WSDLX:安全全局属性

这个新属性指示一个操作是否按照W3C Web体系结构规范被认为是“安全的”,该规范声明:

“……安全交互是指代理人在交互之外不承担任何义务。代理人可以通过其他方式(如签订合同)承担义务。如果代理人在安全交互之前不承担义务,那么在安全交互之后也不承担该义务。

其他Web交互更像订单而不是查询。这些不安全的交互可能会导致资源状态的改变,用户可能会对这些交互的后果负责。不安全的交互包括订阅时事通讯,发布到列表或修改数据库。注意:在本文中,“不安全”一词并不一定意味着“危险”……

换句话说,如果一个操作执行类似于只读函数的操作,它不会永久改变服务环境的任何部分,或者它不会给使用者任何新的义务,那么它就被认为是“安全的”。

该属性本质上是一种手段,通过该手段,服务契约可以传达特定操作几乎没有与之相关的风险。这在支持服务可发现性原则方面尤其有价值,它鼓励我们改进契约的通信质量。但是,也需要考虑到服务抽象的注意事项。在某些情况下,可能认为有必要完全不允许该属性。

如果允许,重要的是SOA治理过程就位,以管理此设置的潜在更改。如果使用者程序依赖于一个服务操作,假设它是安全的,然后操作的底层功能发生变化,使得它不再被认为是安全的,那么这可能会产生各种负面影响。某些使用者可能还需要以编程方式检索此设置。

的默认值WSDLX:安全属性为“false”。因此,如果该属性不存在,或者如果它被显式地设置为false,那么使用者可以假定该操作是“不安全的”。



故障,过失,和出力故障元素

在WSDL2.0中,故障元素中的第一级子元素接口建造。这提升了故障与操作相同的级别,允许在不同的操作之间重用一个错误消息。

如本例所示,多个操作可以通过参考它们的属性过失出力故障元素。
<types>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://actioncon.com/schema/po"
targetNamespace="http://actioncon.com/schema/po"
elementFormDefault="qualified">
<xsd:element name="invalidOrder"
type="invalidOrderType"/>
<xsd:complexType name="invalidOrderType">
<xsd:sequence>
<xsd:element name="PODate" type="xsd:date"/>
<xsd:element name="OrderID" type="xsd:string"/>
<xsd:element name="Desc" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</types>

 

类型构造定义InvalidOrderType类型,该类型随后由OpChangeOrderOpCancelOrder通过各自的出力故障元素。

 

<interface name="ifPurchaseOrder" extends="tns:ifPurchaseOrderLog" >
<fault name="invalidOrderFault" element="po:invalidOrder"/>
<operation name="opChangeOrder"
pattern="http://www.w3.org/2006/01/wsdl/in-out">
<input messageLabel="In" element="po:purchaseOrder "/>
<output messageLabel="Out" element="po:acknowledgement"/>
<outfault ref="tns:invalidOrderFault" messageLabel="Out/>
</operation>
<operation name="opCancelOrder"
pattern="http://www.w3.org/2006/01/wsdl/in-out">
<input messageLabel="In" element="po:poNumber"/>
<output messageLabel="Out"
element="po:acknowledgement"/>
<outfault ref="tns:invalidOrderFault" messageLabel="Out/>
</operation>
</interface>

 


在接口级别定义错误对于绑定定义特别有益。例如,SOAP错误除了它的错误消息细节之外,可能还有一个错误代码(和子代码)。通过在接口级别定义故障,您可以确保通用错误代码可以跨使用故障的所有操作使用。

例如,当下面示例中的接口绑定到SOAP1.2时,可以为所有无效的订单错误指定一个SOAP错误代码作为“发送者”。

<binding name="bdPurchaseOrder-SOAP12HTTP"
interface="tns:ifPurchaseOrder" >
<fault ref="tns:invalidOrderFault" soap12:code="soap12:Sender"/>
<operation ref="tns:opChangeOrder" .../>
<operation ref="tns:opCancelOrder" .../>
</binding>


在此示例中,使用故障元素绑定到装订元素,因此可适用于绑定定义中的两个操作,从而允许操作重用相同的错误代码。

给定接口和绑定定义的结构,在运行时,如果发现一个无效的订单,返回给发送方的错误消息将显示为如下所示:

<soap:Envelope xmlns:soap=
"http://www.w3.org/2003/05/soap-envelope"
xmlns:po="http://actioncon.com/schema/po" ...>
<soap:Body>
<soap:Fault>
<soap:Code>
<soap:Value>soap:Sender</soap:Value>
</soap:Code>
<soap:Detail>
<po:invalidOrder>
<po:PODate>02-23-2008</po:PODate>
<po:OrderID>1234</po:OrderID>
<po:Desc>
The required order party ID is missing.
</po:Desc>
</po:invalidOrder>
</soap:Detail>
</soap:Fault>
</soap:Body>
</soap:Envelope>


图案信息标签属性

WSDL2.0规范允许在单独的规范中定义消息交换模式,然后将其引入到操作通过新的图案属性。

相关的MEP规范确定了交换的消息数量和顺序。每个消息都可以用消息标签和方向(“入”或“出”)来标识。

使用特定MEP的操作应根据以下规则提供相应数量的消息:
对于每个方向为“in”的消息,将输入元素需要使用信息标签属性设置为“in”。
对于每个方向为“out”的消息,输出量元素是用一个信息标签属性设置为“out”。
的命令输入输出量元素的顺序应该与MEP规范中定义的相应消息的顺序相同。
WSDL2.0使用新的术语来描述MEP。例如,来自WSDL1.1的“请求-响应”MEP现在是“输入-输出”,而“单向”MEP被重命名为“输入”。

信息标签操作的输入,输出或故障元素仅指示消息在MEP中所扮演的角色。例如,设置message-label=“在”对于“输入-输出”MEP意味着消息是“输入-输出”操作的输入消息。(这似乎是多余的,因为输入元素的名称已经表明这是一条输入消息。)

下面是一个使用图案信息标签基于“输入-输出”MEP的操作的属性。

<operation name="opChangeOrder"
pattern="http://www.w3.org/2006/01/wsdl/in-out">
<input messageLabel="In" element="po:purchaseOrder "/>
<output messageLabel="Out" element="po:acknowledgement"/>
</operation>


服务和端点定义

在WSDL2.0中,一个服务元素只能通过其接口属性,如下例所示。这意味着当一个服务有多个端点元素,它们将共享一个接口但使用不同的绑定和地址。

这是因为它们是可选的,因为每个端点可以通过不同的绑定配置提供相同的行为。通过允许服务提供替代端点,消费者有更多的自由来确定哪个端口对于给定的目的是最佳的。

<service name="svPurchaseOrder" interface="ifPurchaseOrder">
<endpoint name="purchaseOrder-http-soap12"
binding="tns:bdPO-SOAP12HTTP" address=
"http://actioncon.com/services/soap12/purchaseOrder"/>
</service>



完整的WSDL2.0定义

下面的示例代码显示了完整的WSDL2.0定义。突出显示的部分指出WSDL2.0语言与WSDL1.1的不同之处。

<descriptiontargetNamespace="http://actioncon.com/contract/po"
xmlns="8http://schemas.xmlsoap.org/wsdl/"
xmlns:tns="http://actioncon.com/contract/po"
xmlns:po="http://actioncon.com/schema/po"
xmlns:soapbind="http://www.w3.org/ns/wsdl/soap">

<!- BEGIN ABSTRACT DESCRIPTION ->
<types>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://actioncon.com/schema/po"
targetNamespace="http://actioncon.com/schema/po"
elementFormDefault="qualified">
<xsd:element name="purchaseOrder" type="PurchaseOrderType"/>
<xsd:element name="acknowledgement" type="xsd:string"/>
<xsd:element name="poNumber" type="xsd:integer"/>
<xsd:element name="status" type="xsd:string"/>
<xsd:complexType name="PurchaseOrderType">
<xsd:sequence>
<xsd:element ref="poNumber"/>
<xsd:element name="PODate" type="xsd:date"/>
<xsd:element name="BillToParty" type="PartyType"/>
<xsd:element name="ShipToParty" type="PartyType"/>
<xsd:element name="LineItems" type="LineItemsType"/>
</xsd:sequence>
<xsd:attribute name="version" type="xsd:decimal"/>
</xsd:complexType>
<xsd:complexType name="PartyType">
<xsd:sequence>
<xsd:element name="ID" type="xsd:integer"/>
<xsd:element name="PartyName" type="xsd:string"/>
<xsd:element name="ContactName" type="xsd:string"/>
<xsd:element name="Phone" type="xsd:string"/>
<xsd:element name="Address" type="AddressType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="AddressType">
<xsd:sequence>
<xsd:element name="Line1" type="xsd:string"/>
<xsd:element name="Line2" type="xsd:string"
minOccurs="0"/>
<xsd:element name="City" type="xsd:string"/>
<xsd:element name="State" type="xsd:string"/>
<xsd:element name="PostalCode" type="xsd:string"/>
<xsd:element name="Country" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="LineItemsType">
<xsd:sequence>
<xsd:element name="LineItem" type="LineItemType"
maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="LineItemType">
<xsd:sequence>
<xsd:element name="ProductID" type="ProductIDType"/>
<xsd:element name="ProductName" type="xsd:string"/>
<xsd:element name="Quantity" type="xsd:int"/>
<xsd:element name="Price" type="PriceType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:simpleType name="ProductIDType">
<xsd:restriction base="xsd:string">
<xsd:pattern value="[A-Z]{2}[0-9]{4}"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="PriceType">
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="8"/>
<xsd:fractionDigits value="2"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
</types>
<interface name="ifPurchaseOrder">
<operation name="opSubmitOrder"
pattern="http://www.w3.org/2006/01/wsdl/in-out">
<input messageLabel="In" element="po:purchaseOrder"/>
<output messageLabel="Out" element="po:acknowlegement"/>
</operation>
<operation name="opCheckOrderStatus"
pattern="http://www.w3.org/2006/01/wsdl/in-out">
<input messageLabel="In" element="po:poNumber"/>
<output messageLabel="Out" element="po:status"/>
</operation>
<operation name="opChangeOrder"
pattern="http://www.w3.org/2006/01/wsdl/in-out">
<input messageLabel="In" element="po:purchaseOrder "/>
<output messageLabel="Out" element="po:acknowledgement"/>
</operation>
<operation name="opCancelOrder"
pattern="http://www.w3.org/2006/01/wsdl/in-out">
<input messageLabel="In" element="po:poNumber"/>
<output messageLabel="Out" element="po:acknowledgement"/>
</operation>
</interface>
<!- END ABSTRACT DESCRIPTION ->

<!- BEGIN CONCRETE DESCRIPTION ->
<binding name="bdPO-SOAP12HTTP" interface="ifPurchaseOrder"
type="http://www.w3.org/2006/01/wsdl/soap"
soapbind:protocol=
"http://www.w3.org/2003/05/soap/bindings/HTTP">
<operation ref="tns:opSubmitOrder"
soapbind:mep=
"http://www.w3.org/2003/05/soap/mep/request-response"
soapbind:action=
"http://actioncon.com/submitOrder/request"/>
<operation ref="opCheckOrderStatus"
soapbind:mep=
"http://www.w3.org/2003/05/soap/mep/request-response"
soapbind:action=
"http://actioncon.com/checkOrder/request"/>
<operation ref="opChangeOrder"
soapbind:mep=
"http://www.w3.org/2003/05/soap/mep/request-response"
soapbind:action=
"http://actioncon.com/changeOrder/request"/>
<operation ref="opCancelOrder"
soapbind:mep=
"http://www.w3.org/2003/05/soap/mep/request-response"
soapbind:action=
"http://actioncon.com/cancelOrder/request"/>
</binding>

<service name="svPurchaseOrder" interface="ifPurchaseOrder">
<endpoint name="purchaseOrder-http-soap12"
binding="tns:bdPO-SOAP12HTTP" address=
"http://actioncon.com/services/soap12/purchaseOrder"/>
</service>
<!- END CONCRETE DESCRIPTION ->

</description>


结论

WSDL2.0对表达Web服务契约的结构和语言进行了一些重大的更改。如果您能够利用这些变化,其中一些变化可能会被证明是有益的,而其他一些变化可能会造成不必要的干扰。最好的办法是充分了解各种选择,然后做出明智的决定。



参考文献

[REF-1]“Web Service Contract Design and Versioning for SOA”作者:Thomas Erl,Anish Karmarkar,Priscilla Walmsley,Hugo Haas,Umit Yalcinalp,Canyang Kevin Liu,David Orchard,Andre Tost,James Pasley,http://www.soabooks.com/wsc/

本文最初发表在SOA杂志(www.soamag.com),与“Thomas ERL的Prentice Hall面向服务的计算系列”(www.soabooks.com)。版权所有©SOA系统有限公司(www.soasystems.com