相对EndpointReference而言,个人认为在WS-Addressing规范中Message Addressing Properties的作用显的更加重要,下面将对它做详细介绍。与EndpointReference用于描述服务的地址不同,Message Addressing Properties作为SOAP Head的扩展将包含在每一个SOAP 消息中,用于该消息的寻址。首先来看一下它的XML Infoset:
<wsa:To>xs:anyURI</wsa:To> ?
<wsa:From>wsa:EndpointReferenceType</wsa:From> ?
<wsa:ReplyTo>wsa:EndpointReferenceType</wsa:ReplyTo> ?
<wsa:FaultTo>wsa:EndpointReferenceType</wsa:FaultTo> ?
<wsa:Action>xs:anyURI</wsa:Action>
<wsa:MessageID>xs:anyURI</wsa:MessageID> ?
<wsa:RelatesTo RelationshipType="xs:anyURI"?>xs:anyURI</wsa:RelatesTo> *
<wsa:ReferenceParameters>xs:any*</wsa:ReferenceParameters> ?
下面这张图更加清楚的表示出Message Addressing Properties与SOAP 消息的关系。
其中<wsa:MessageID>用于标识一个消息,而<wsa:RelatesTo>表示该消息与另一消息关系,元素值是另一消息的MessageID。<wsa:RelatesTo>元素对实现异步消息交换有很重要的作用,这点在后面的文章中会具体介绍。
我把剩下的Message Addressing Properties分成了两类属性,一类(Go)指出该消息的去向,另一类(Back)为该消息可能存在的返回消息提供寻址功能。也就是说Go类型的属性才与该消息的寻址直接相关,而Back类型的属性对消息自身的寻址没有任何影响,纯粹是为了与该消息对应的返回消息寻址所用。显而易见,如果该消息不存在返回消息,那么Back类型的属性就不需要了。下面具体介绍每一类属性。
Go类型的属性用于消息自身的寻址,自然也是最重要的,在了解了EndpointReference的概念后,对于其中的<wsa:To>和<wsa:ReferenceParameters>属性也就很容易理解了。把消息所请求的Service的EndpointReference的值搬过来就行了,如下图所示:
而另一个属性<wsa:Action>则显得比较陌生,还记得通过Http协议访问Web Services时Http Head中的SOAPAction元素吗?
POST /TravelAgentServices/Hotel.asmx HTTP/1.1
Host: localhost
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://idior.cnblogs.com/hotel/PlaceOrder"
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope>
...
</soap:Envelope>
<wsa:Action>此时的作用与SOAPAction相当,现在的问题就在于这个Action的值从何而来?要想知道答案,首先需要了解<wsa:Action>的作用。假设你在SOAP消息中包含了一个订单,当这个消息达到Service之后,你希望它怎么处理这个订单呢?是为你新增这个订单,还是将这个订单删除,还是更新?同一个消息,Service可能提供了多种处理方法,你希望Service对你所发送的消息如何处理?在消息中指定处理该消息的语义,这就是<wsa:Action>所起的作用。说白了,就是通过<wsa:Action>指定消息到达Service时,究竟触发服务中的哪个方法完成对消息的处理。
知道了<wsa:Action>用于指定将处理该消息的方法,那么不难想象它的值来自于WSDL。
它的构成如下:
[target namespace][delimiter][port type name][delimiter][input|output name]
看了下面的例子就很容易明白了:
<definitions targetNamespace="http://idior.cnblogs.com/resSvr">
...
<portType name="reservationInterface">
<operation name="opCheckAvailability">
<input message="tns:checkAvailability" name="CheckAvailability"/>
<output message="tns:checkAvailabilityResponse" name="Availability"/>
</operation>
</portType>
...
</definitions>
[targetNamespace] = http://idior.cnblogs.com/resSvr
[port type name] = reservationInterface
[input name] = CheckAvailability
[output name] = CheckAvailabilityResponse
Applying the pattern above with these values we have:
input action = http://idior.cnblogs.com/resSvr/reservationInterface/CheckAvailability
output action = http://idior.cnblogs.com/resSvr/reservationInterface/CheckAvailabilityResponse
当然一种更简单明了的方法就是在WSDL中直接指定某个方法的输入输出消息的Action,如下所示:
<definitions targetNamespace="http://idior.cnblogs.com/resSvc" ...>
...
<portType name="reservationInterface">
<operation name="opCheckAvailability">
<input message="tns:checkAvailability"
wsa:Action="http://idior.cnblogs.com/resSvc/CheckAvailability"/>
<output message="tns:checkAvailabilityResponse"
wsa:Action="http://idior.cnblogs.com/resSvc/CheckAvailabilityResponse"/>
</operation>
</portType>
...
</definitions>
综合得到Message Addressing Properties中Go类型的属性设定,如下图所示:
从以上介绍的Message Addressing Properties中的属性可以看出,WS-Addressing规范就是把原来处于传输层的寻址信息提升到更高层的消息层面,直接在SOAP消息中包含这些信息,这样就可以摆脱对特定传
输协议的约束,从而使得SOAP消息的传输与具体传输协议无关,这也是Loosely Coupled的体现之一。
Request- Response Pattern in WS-Addressing
Request-Response 消息交换模式(Message Exchange Pattern)是最经典也是最常用的MEP。在Request-Reply MEP中涉及两个消息-Request Message与Response Message。通常我们使用Http协议访问某个Web Service时,就是采用的这个消息交互模式。不过除了使用Http协议的同步式Request-Response MEP,还有借助诸如TCP,SMTP,MSMQ协议的异步式Request-Response MEP。下面就将分别对Request Message与Response Message中Message Addressing Properties在同步式和异步式下的内容做详细介绍。
Request Message
在之前对Message Addressing Properties中Go类型的属性的介绍中,并没有涉及所采用的MEP,其实上述的介绍仍适用于Request-Response MEP,因此不论在Request Message还是Response Message中有关Go类型属性的设定方法都如前所述,只不过它们各自所依据的EndpointReference不同罢了。因此现在重点需要了解在 Request Message中Back类型的属性如何设定。Back类型的属性的值都是EndpointReference类型,其中<wsa:From>则表示发送该Request Message的地址,<wsa:ReplyTo>指定了该Request Message的Response Message将发向的地址,这个值可能与<wsa:From>相同也可能不同。FaultTo则指出当消息处理出现错误时错误消息将去往的地址。在这其中<wsa:ReplyTo>属性是必须的。其实在Http这种同步式Request- Response的MEP中,因为请求和回应都是使用的同一信道,所以并不需要<wsa:ReplyTo>属性,不过为了形式上的统一,WS-Addressing规范还是强制了在Request- Response的MEP下<wsa:ReplyTo>属性不能为空。这样也方便Service辨识Client的MEP,如果ReplyTo有值则是Request-Response,如果没有则是OneWay。对于同步式的Request-Response MEP,你可以采用"http://www.w3.org/2005/08/addressing/anonymous"来设定<wsa:ReplyTo>的值, 如果你另外设定一个EndpointReference, 那么Service会关闭当前的Http连接,利用刚设定的EndpointReference新建一个连接用于发送Response Message。
为了使得在异步情况下,Response Message能够通过<wsa:RelatesTo>属性与Request Message关联上,Request Message中<wsa:MessageID>属性也是必须的。
下图显示了如何构造Request Message的Message Addressing Properties:
Response Message
Response Message中Go类型的属性的设定来源于Request Message中的<wsa:ReplyTo>属性,<wsa:ReplyTo>的类型也是EndpointReference,因此除了EndpointReference的指向不同,Response Message中Go类型属性的设定与Request Message基本一致,不过需要注意此时的<wsa:Action>属性是采用的WSDL中Output参数的<wsa:Action>值。在采用异步式的Request-Response MEP时,由于Client发出Request Message的和接受Response Message的动作并不处于同一个线程,为了让Client在接受到的Response Message后能够将其与Request Message关联上,此时将使<wsa:RelatesTo>指向Request Message中的<wsa:MessageID>。
下图显示了如何构造Response Message的Message Addressing Properties: