梦想与现实的落差,就是我们离成功的距离!!

博客园 首页 新随笔 联系 订阅 管理
 

Web 服务最佳实践

概要

Web服务是作为一种沟通技术而被很好地制订出来,它为Internet提供最佳的互通能力。它们的标准化进程正高速地进行着,这必将引起它们会被更广泛的接受。尽管如此,从许多邮件列表、用户组和各种讨论来判断,在不同Web服务设计(Web Service Design)方法中仍然存在相当多的混乱情形。“Document/Literal” 意味着什么,而“RPC-style”又是什么,怎样使SOAP“message-style” 适合这呢?

这篇文章将会阐明和详细解释那些由Web服务标准化组定义的不同的Web服务设计方法学,阐明各种术语,着重解释它们的不同之处。在这里,我们将把精力放在如下的几个Web服务设计方法学,评估它们的优点和缺点,并在设计一种互通性Web服务中探究每一种类型得到多大程度的支持。

  1. RPC/Encoded 样式
  2. RPC/Literal 样式
  3. Document/Literal 样式
  4. Document /Literal 外覆样式

介绍

在市场上Web服务在相对存在较短的时间内,得到了巨大的认同和广泛的应用。其中一个主要原因当然是它们的那些非常早期的开放式标准,而这些标准就是市场上所有主要的Web服务推崇者所推动的;另一方面,在Web服务看起来应该像什么和他们应该如何通信这些方面,这些推崇者各有自己的偏爱。这已经导致今天的标准支持各种不同的关于web服务消息能怎样格式化和它们如何通信的方法,事实上,那些不同的通信类型是需要的。

这些描述和使用Web服务的相关标准是WSDL(Web服务描述语言),一种标准的类似XML Schema的语言,用它详细说明Web服务和简单对象访问协议(SOAP),Web服务使用的实际的沟通协议就是简单对象访问协议(SOAP)。在了解真正的设计方法学之前,让我们先阐述下在web服务领域中频繁使用到的各种术语。

沟通模式

让我们从沟通模式开始,在使用Web服务时我们应能本质地区别三种沟通方法:

  • 远程进程调用:客户端给服务提供者发送一个SOAP请求并等待一个SOAP响应(同步沟通)。
  • 发送消息: 客户端发送一个SOAP请求但不期望有SOAP响应返回(单向沟通)。
  • 异步回调: 一个客户端用上述方法中的一种调用服务。然后,双方为回叫调用交换角色。这种模式能建立在前面两种模式之上。

SOAP 协议格式化规则

现在我们转到一个Web服务的SOAP的消息(本质上是消息的<soap:body> 元素)能如何格式化,WSDL1.1 区分两种不同绑定形式(参考soap的绑定形式):RPCDocument(文档)。(译者注:RPC(消息包含参数并返回值)Document(消息包含文档)

  • RPC 样式

RPC样式指定<soap:body> 元素包含一个将被调用的web方法的名称的元素(wrapper element(封装元素))。这个元素依次为该方法的每个参数还有返回值作了记录。

  • Document 样式

如果是document 样式,就没有像在RPC样式中的wrapper元素。转而代之的是消息片断直接出现在<soap:body> 元素之下。没有任何SOAP格式化规则规定<soap:body>元素下能包含什么;它包含的是一个发送者和接收者都达成一致的XML文档。

第二种格式规则就是Use属性。这与各种类型如何在XML中显示有关,它指定使用某种编码规则对消息片段进行编码,还是使用消息的具体架构来定义片段。如下就是提供的两种选择:

  • 编码

如果use的值是encoded”, 则每个消息片段将使用类型属性来引用抽象类型。通过应用由 encodingStyle 属性所指定的编码样式,可使用这些抽象类型生成具体的消息。最常用到的SOAP编码样式是在SOAP1.1中定义的一组序列化规则,它说明了对象、结构、数组和图形对象应该如何序列化。通常,在应用程序中使用SOAP编码着重于远程进程调用和以后适合使用RPC消息样式。

  • Literal

如果use 的值是Literal 则每个片段使用 element 属性(对于简单片段)或 type 属性(对于复合片段)来引用具体架构,例如,数据根据指定的架构来序列化,这架构通常使用W3C XML架构来表述。

1总结了各种不同的web服务参数的可选项。一个重要的事实就是,每个web服务开发人员要做三个独立的决定,使用什么“沟通模式”?什么SOAP格式化“样式”?最后用到什么SOAP消息编码类型?

 

WSDL 参数

可用选项

Communication Patterns

远程进程调用或单方消息发送

Style

Document RPC

Use

Encoded Literal

1.Web服务参数。

虽然,理论上说,这些选项的任何一种组合都是可以的,但在实践中会明确偏爱某种组合而不是其它的,同时,各种标准和Web服务互用性组织(WS-I)也有某种明确的偏爱。

因此在实践中,仅Document/Literal RPC/Encoded 得到了广泛的应用,同时也被大部分平台直接支持,这些平台显示在表2中。这个表也显示了对不同的style/use组合的WS-I 一致性测试结果。

Style/Use 组合

支持的 Soap 工具

WS-I 一致性

RPC/Encoded

Microsoft, Axis 1.1

Failed

RPC/Literal

Axis 1.1

Failed

Document/Literal

Microsoft , Axis1.1

Passed

2. Web服务格式支持

由于Document/Encoded这种组合不支持现有使用的平台,所以没有测试。事实上Document/Encoded组合还没有真实的应用环境。

一个简单Web服务例子

现在我们来更详细的了解被使用和支持最多的RPC/EncodedDocument/Literalstyle/use组合。我们将利用一个叫做SendTemperatureweb方法举例来说明每一种的style/use组合,那个web方法使用的参数是一个用户自定义的复杂对象,返回一个void类型,这些在清单1中有描述。

我们选择了这么一个使用复杂数据类型例子,就是为了让各种样式之间的不同更加明显。

public void SendTemperature (Temperature[] TempCollection){}

public class Temperature 

{

   
/// <remarks/>

   
public int Id;

  
/// <remarks/>

  
public string Name;

  
/// <remarks/>

  
public System.Double Temperature;

}

清单1. 使用C#实现的web方法SendTemperature

针对这个web方法,我们将展示各种web服务样式就它们各自的SOAP请求形式怎样在WSDL中中实现,重点讲述它们的不同之处。我们利用Microsoft VS.NETAxis SOAP 工具箱来实现。

注意,为了简单,在这篇文章中我们忽略了WSDL文件的名称空间、前缀和服务部分。清单2列出了常用的名称空间和前缀。

xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" 

xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 

xmlns:s="http://www.w3.org/2001/XMLSchema" 

xmlns:s0="http://interop.webservices.fhso.ch/{service name}" 

xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" 

xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/" 

xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" 

xmlns="http://schemas.xmlsoap.org/wsdl/" 

targetNamespace="http://interop.webservices.fhso.ch/{service name}/ ”

清单2. 名称空间和使用到的前缀

  1. RPC/Encoded 样式

实质上RPC/Encoded 是一种典型的遵循“远程进程调用”模式的样式,在这种模式中客户端发送一个同步请求给服务器来执行一次操作。SOAP请求包含了要执行的方法的名称和它携带的参数。运行web服务的的服务器把该请求转化成适当的对象,然后执行操作并向客户端做出响应反馈一个SOAP消息。在客户端,该响应被用来合成一个适当的对象并返回给客户端所需要的的信息。在RPC样式的web服务中,整个方法在WSDL文件和SOAP体中被指定,包含方法的发送参数和返回值。因此我们用这种样式会有相当紧密的耦合关系。

清单3显示在RPC/Encoded样式中SendTemperature WSDL定义。

<types>

<s:schema targetNamespace="http://interop.webservices.fhso.ch/rpcencoded">

<s:complexType name="ArrayOfTemperature">

<s:complexContent mixed="false">

<s:restriction base="soapenc:Array">

<s:attribute d7p1:arrayType="s0:Temperature[]" ref="soapenc:arrayType" 

xmlns:d7p1
="http://schemas.xmlsoap.org/wsdl/"/>

</s:restriction>

</s:complexContent>

</s:complexType>

<s:complexType name="Temperature">

<s:sequence>

<s:element minOccurs="1" maxOccurs="1" name="Id" type="s:int"/>

<s:element minOccurs="1" maxOccurs="1" name="Name" type="s:string"/>

<s:element minOccurs="1" maxOccurs="1" name="value" type="s:double"/>

</s:sequence>

</s:complexType>

</s:schema>

</types>

<message name="SendTemperatureSoapIn">

<part name="Collection" type="s0:ArrayOfTemperature"/>

</message>

<message name="SendTemperatureSoapOut"/>

<portType name="TemperatureRpcEncodedSoap">

<operation name="SendTemperature">

<input message="s0:SendTemperatureSoapIn"/>

<output message="s0:SendTemperatureSoapOut"/>

</operation>

</portType>

<binding name="TemperatureRpcEncodedSoap" type="s0:TemperatureRpcEncodedSoap">

<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>

<operation name="SendTemperature">

<soap:operation soapAction="http://interop.fhso.ch/soapformat/SendTemperature"/>

<input>

<soap:body use="encoded" 

      encodingStyle
="http://schemas.xmlsoap.org/soap/encoding/"/>

</input>

<output>

<soap:body use="encoded" 

      encodingStyle
="http://schemas.xmlsoap.org/soap/encoding/"/>

</output>

</operation>

</binding>

清单3. SendTemperatureRPC/Encoded 样式中的SOAP定义

注意绑定的style的值被设为rpcuse的值是encoded’. <message> 这节中,可以有任意数目的<part> 元素,该元素包含一个type 属性,对rpc样式来说,该属性的值是惟一的。现在我们看看调用这个SendTemperature web方法会发生什么,传送的参数是包含两个元素的数组。清单4显示了SOAP消息形式的结果。

 

<soap:Envelopexmlns:

     
soap="http://schemas.xmlsoap.org/soap/envelope/" 

     xmlns:soapenc
="http://schemas.xmlsoap.org/soap/encoding/" 

     xmlns:tns
="http://interop.webservices.fhso.ch/rpcencoded" 

     xmlns:types
="http://interop.webservices.fhso.ch/rpcencoded/encodedTypes" 

     xmlns:xsi
="http://www.w3.org/2001/XMLSchema-instance" 

     xmlns:xsd
="http://www.w3.org/2001/XMLSchema">

<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">

<SendTemperature>

<Collection href="#id1"/>

</SendTemperature>

<soapenc:Array id="id1" soapenc:arrayType="tns:Temperature[2]">

<Item href="#id2"/>

<Item href="#id3"/>

</soapenc:Array>

<tns:Temperature id="id2" xsi:type="tns:Temperature">

<Id xsi:type="xsd:int">3</Id>

<Name xsi:type="xsd:string">Station1</Name>

<value xsi:type="xsd:double">34.3</value>

</tns:Temperature>

<tns:Temperature id="id3" xsi:type="tns:Temperature">

<Id xsi:type="xsd:int">56</Id>

<Name xsi:type="xsd:string">Station3</Name>

<value xsi:type="xsd:double">23.6</value>

</tns:Temperature>

</soap:Body>

</soap:Envelope>

清单4. SendTemperatureRPC/Encoded 样式中的SOAP消息

SOAP消息中每个参数都会被类型编码(译者注:例如xsi:type="xsd:int",注意,在SOAP消息中的href’ tags 标签,实质上也是RPC/Encoded样式的一部分,它被用来查询数组中的元素。在任何literal 样式中,这个href标签是不可用的。让我们来分析下WSDL定义和它的SOAP消息形式。

优点:

    • WSDL文件的定义遵循直观和众所周知的远程进程调用的沟通模式。
    • 操作名显示在消息中,因此接收者很容易就把消息分派给它的实现。
    • 如果你正在你的服务中使用数据图形或者多态,在本文描述的样式中这是惟一能使用的样式。

缺点:

    • SOAP消息包含的类型编码信息就如xsi:type="xsd:int", xsi:type="xsd:string", xsi:type="xsd:double" ,这些就是一种开销。
    • 通常验证SOAP消息是很困难的。
    • RPC样式引起了一种在服务提供者和客户之间的紧密耦合,任何对接口的更改都会导致服务和客户间联系的中断。
    • 依赖那也许也许要同步处理的信息,内存约束也许使得RPC消息传输不能实现,因为在内存中发生消息聚集。
    • 不被WSI一致性标准所支持。

现在我们来看同样的web方法用RPC/Literal样式实现并看看它是否能消除RPC/Encode样式中的一些缺陷。

  1. RPC/Literal 样式

这里的WSDL定义看起来和先前的非常相似,惟一可预见的改变就是<soap:body> 元素中use的值由encoded变为literal,这显示在清单5中。就如上面所描述的,这就意味着数据类型定义并是由引用的XML Schema所提供,而不是RPC编码。

 

<types>

<s:schema elementFormDefault="qualified" 

targetNamespace
="http://interop.webservices.fhso.ch/rpcliteral">

<!-- there are no global element declarations. There's nothing in the 

schema that completely describes the content of soap:Body 
-->

<s:complexType name="ArrayOfTemperature">

<s:sequence>

<s:element minOccurs="0" maxOccurs="unbounded" name="Temperature" 

     nillable
="true" 

     type
="s0:Temperature"/>

</s:sequence>

</s:complexType>

<s:complexType name="Temperature">

<s:sequence>

<s:element minOccurs="0" maxOccurs="1" name="Id" type="s:int"/>

<s:element minOccurs="0" maxOccurs="1" name="Name" type="s:string"/>

<s:element minOccurs="0" maxOccurs="1" name="value" type="s:double"/>

</s:sequence>

</s:complexType>

</s:schema>

</types>

<message name="SendTemperatureSoapIn">

<part name="Collection" type="s0:ArrayOfTemperature"/>

</message>

<message name="SendTemperatureSoapOut"/>

<portType name="TemperatureRpcLiteralSoap">

<operation name="SendTemperature">

<input message="s0:SendTemperatureSoapIn"/>

<output message="s0:SendTemperatureSoapOut"/>

</operation>

</portType>

<binding name="TemperatureRpcLiteralSoap" 

            type
="s0:TemperatureRpcLiteralSoap">

<soap:binding style="rpc" 

            transport
="http://schemas.xmlsoap.org/soap/http"/>

<operation name="SendTemperature">

<soap:operation 

            
soapAction="http://interop.fhso.ch/soapformat/SendTemperature"/>

<input>

<soap:body use="literal" 

            namespace
="http://interop.fhso.ch/soapformat/SendTemperature"/>

</input>

<output>

<soap:body use="literal" />

</output>

</operation>

</binding>

清单 5. SendTemperatureRPC/Literal 样式中的SOAP定义

然而,使用这种样式仍然存在一个主要的缺陷。独立的XML Schema 不会告诉你消息体中的信息集合包含了些什么,你也必需知道RPC规则。因此,该schema描述的一种RPC/Literal消息但并不足以验证那种消息。

在清单6中让我们看看针对RPC/Literal样式的SOAP消息形式。注意,类型编码被完全移除掉了。

 

<soapenv:Envelope

xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 

xmlns:xsd
="http://www.w3.org/2001/XMLSchema" 

xmlns:xsi
="http://www.w3.org/2001/XMLSchema-instance">

<soapenv:Body>

< ! – SendTemperature is the name of the procedure being invoked. 

Collection is a parameter of that procedure.

Note that Collection is not namespace qualified. The two Temperature 

elements are contents of the Collection parameter. This Collection can 

be thought of as an array of Temperature items. Note that the Temperature 

is namespace qualified but is in a different namespace than SendTemperature. 

These namespace rules are unique to RPC-style messages -- 
> 

<SendTemperature xmlns="http://interop.fhso.ch/soapformat/SendTemperature">

<Collection xmlns="">

<ns1:Temperature xmlns:ns1="http://interop.webservices.fhso.ch/rpcliteral">

<ns1:Id>2</ns1:Id>

<ns1:Name> Station1</ns1:Name>

<ns1:value>34.2</ns1:value>

</ns1:Temperature>

<ns2:Temperature xmlns:ns2="http://interop.webservices.fhso.ch/rpcliteral">

<ns2:Id>56</ns2:Id>

<ns2:Name> Station 3</ns2:Name>

<ns2:value>23.6</ns2:value>

</ns2:Temperature>

</Collection>

</SendTemperature>

</soapenv:Body>

</soapenv:Envelope>

清单 6. SendTemperatureRPC/Literal 样式中的SOAP消息

优点:

    • WSDL定义仍然像RPC/Encoded样式一样简单直接。
    • 操作名仍然出现在SOAP消息中。
    • 把类型编码从消息中排除了,因此提升了吞吐性能。

缺点:

    • 服务和客户之间仍然有紧密耦合。
    • 仍然难以用SOAP消息来验证传输的数据。
    • 它也不被WSI一致性标准所支持。

现在,我们来看看Document/Literal样式,来看一下该样式是否能减少现有的缺陷。

  1. Document/Literal样式

Document样式和上面的RPC样式最主要的不同就是,前者中客户在一个规范的XML文档中向服务器发送服务参数,而代替了后者中的一组离散的方法的参数值。这使得Document样式比RPC样式有更加松散的耦合关系。

Web服务提供者处理规范的XML文档,执行操作并向客户端作出响应,返回的也是一个规范的XML文档。在服务器对象(参数,方法调用等)和XML数据值之间并没有一种直接的映射关系。应用程序负责映射XML数据值。Document样式中SOAP消息在它的SOAP体中包含了一个或者更多的XML文档。协议并没有约束文档需要如何组织构成;这完全是在程序级处理的。另外,Document样式web服务遵循异步处理范例。

就像在清单7中显示的那样,相比RPC样式,该样式的WSDL定义有了很大的改变。

<types>

<s:schema elementFormDefault="qualified" 

     targetNamespace
="http://interop.webservices.fhso.ch/docLit">

< ! - - this element declaration describes the entire contents 

of the soap:Body in the request message.

This is a feature of document/Literal that RPC/Literal lacks - -
> 

<s:element name="Collection">

<s:complexType>

<s:sequence>

<s:element minOccurs="0" maxOccurs="unbounded" name="Temperature" 

   nillable
="true" 

   type
="s0:Temperature"/>

</s:sequence>

</s:complexType>

</s:element>

<s:complexType name="Temperature">

<s:sequence>

<s:element minOccurs="0" maxOccurs="1" name="Id" type="s:int"/>

<s:element minOccurs="0" maxOccurs="1" name="Name" type="s:string"/>

<s:element minOccurs="0" maxOccurs="1" name="value" type="s:double"/>

</s:sequence>

</s:complexType>

< ! – Similarly this element declaration describes 

the contents of the soap body in the response 

message. In this case the response is empty -- 
> 

<s:element name="SendTemperatureResponse">

<s:complexType/>

</s:element>

</s:schema>

</types>

<message name="SendTemperatureSoapIn">

<part name="parameters" element="s0:Collection"/>

</message>

<message name="SendTemperatureSoapOut">

<part name="parameters" element="s0:SendTemperatureResponse"/>

</message>

<portType name="TemperatureDocLitSoap">

<operation name="SendTemperature">

<input message="s0:SendTemperatureSoapIn"/>

<output message="s0:SendTemperatureSoapOut"/>

</operation>

</portType>

<binding name="TemperatureDocLitSoap" type="s0:TemperatureDocLitSoap">

<soap:binding style="document" 

  transport
="http://schemas.xmlsoap.org/soap/http"/>

<operation name="SendTemperature">

<soap:operation soapAction=

   "http://interop.webservices.fhso.ch/documentliteral/SendTemperature"
 

style
="document"/>

<input>

<soap:body use="literal" />

</input>

<output>

<soap:body use="literal" />

</output>

</operation>

</binding>

清单 7. SendTemperature Document/Literal样式中 WSDL 定义.

注意,绑定style 的值是document以及 use 的值是literal. message这一节中,仅可能有一个<part> 元素,该元素包含了一个叫做element的属性。

这片断指出一个描述了soap体的全部内容的schema元素申明。注意,现在集合被定义为一个元素而不上一种类型。Document/Literal样式的主要特点,相比RPC/Literal样式的关键有益之处就是schema 元素申明完全描述了<soap:body>的内容。这样就意味着你只通过查看schema而不要任何附加规则就能说出消息体信息集中包含了什么。因此你就能接收schema描述一个Document/Literal消息并用它验证消息,这可是用RPC/Literal样式无法完成的。

现在让我们来看看在清单8中该样式相应的SOAP消息形式。注意,没有指定类型编码数据,还有操作名也消失了。

 

<soap:Envelope 

xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 

xmlns:xsi
="http://www.w3.org/2001/XMLSchema-instance" 

xmlns:xsd
="http://www.w3.org/2001/XMLSchema">

<soap:Body>

< -- note that the Operation name is missing in the message -- >

<Collection xmlns="http://interop.webservices.fhso.ch/docLit">

<Temperature>

<Id>2</Id>

<Name>Station 1</Name>

<value>34.2</value>

</Temperature>

<Temperature>

<Id>56</Id>

<Name>Station 3</Name>

<value>23.5</value>

</Temperature>

</Collection>

</soap:Body>

</soap:Envelope>

清单 8. SendTemperature Document/Literal 样式中SOAP 消息

下面就是对这种样式的优点和缺点的总结。

优点:

    • SOAP消息中没有类型编码信息。
    • 你总能用任何XML验证器来验证消息,在soap体中任何东西都在schema中有定义。
    • 使用document样式,规则不是那么严格,还有对XML Schema进行增强和更改时不会破坏接口。
    • 如果使用某特殊序列进行多进程调用,Document 样式可以保持应用程序的状态。
    • Document样式更加适合异步处理。
    • 许多document-messaging服务能够选择文档的DOMSAX 两种处理方式的其中一种,结果就是能最小化在内存中的处理。

缺点:

    • WSDL定义变得更加复杂。
    • SOAP消息中的操作名没有了,没有了名称,把消息分派给它的实现方法就变得困难或不可能了。

我们已经看到Document/Literal 样式消除了许多RPC/Literal样式中的缺点,另一方面,它也引入了一个新的缺点:在SOAP消息中丢失了操作名。

由于第四种样式选项,Document/Encoding样式,没有实际使用,将不对它进行描述了。而是我们将看看Document/Literal样式的扩展,即Document/Literal外覆样式。

  1. Document/Literal 外覆样式

该样式被微软推荐来消除因标准的Document/Literal 样式引起的缺点。虽然在WSDL1.1标准中没有对该样式进行说明,但现在许多SOAP工具都支持它。

让我们看清单9中的WSDL定义,以及清单10中相应的SOAP消息。

 

<types>

<s:schema elementFormDefault="qualified" 

targetNamespace
="http://interop.webservices.fhso.ch/docLitWrapped">

<s:element name="SendTemperature">

<s:complexType>

<s:sequence>

<s:element minOccurs="0" maxOccurs="1" name="Collection" 

type
="s0:ArrayOfTemperature"/>

</s:sequence>

</s:complexType>

</s:element>

<s:complexType name="ArrayOfTemperature">

<s:sequence>

<s:element minOccurs="0" maxOccurs="unbounded" name="Temperature" 

  nillable
="true" 

  type
="s0:Temperature"/>

</s:sequence>

</s:complexType>

<s:complexType name="Temperature">

<s:sequence>

<s:element minOccurs="0" maxOccurs="1" name="Id" type="s:int"/>

<s:element minOccurs="0" maxOccurs="1" name="Name" type="s:string"/>

<s:element minOccurs="0" maxOccurs="1" name="value" type="s:double"/>

</s:sequence>

</s:complexType>

<s:element name="SendTemperatureResponse">

<s:complexType/>

</s:element>

</s:schema>

</types>

<message name="SendTemperatureSoapIn">

<part name="parameters" element="s0:SendTemperature"/>

</message>

<message name="SendTemperatureSoapOut">

<part name="parameters" element="s0:SendTemperatureResponse"/>

</message>

<portType name="TemperatureDocLitWrappedSoap">

<operation name="SendTemperature">

<input message="s0:SendTemperatureSoapIn"/>

<output message="s0:SendTemperatureSoapOut"/>

</operation>

</portType>

<binding name="TemperatureDocLitWrappedSoap" 

   type
="s0:TemperatureDocLitWrappedSoap">

<soap:binding style="document" 

   transport
="http://schemas.xmlsoap.org/soap/http"/>

<operation name="SendTemperature">

<soap:operation soapAction=

  "http://interop.webservices.fhso.ch/docLitWrapped/SendTemperature"
 

  style
="document"/>

<input>

<soap:body use="literal"/>

</input>

<output>

<soap:body use="literal"/>

</output>

</operation>

</binding>

清单 9. SendTemperatureDocument/Literal 外覆样式中的WSDL定义.

首先,注意在清单9中操作名被重新引入到WSDL文件的第一个element标签中,也注意到,在清单10中SOAP消息看起来跟RPC/Literal样式的SOAP消息类似,但是有一个细微的差别,在RPC/Literal样式SOAP消息中<soap:body> 元素的子元素<SendTemperature> 是操作名,而在Document/Literal外覆样式的SOAP消息中<SendTemperature> 是元素名,单一输入消息片断引用该元素,该样式用一种狡猾的方法把操作名重新引入到SOAP消息中。

这些就是document/Literal外覆样式的主要特征:

    • 输入消息有一单一片断
    • 该片断是一个元素
    • 该元素同操作有相同的名字
    • 该元素的复杂类型没有属性

 

<soap:Envelope 

xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 

xmlns:xsi
="http://www.w3.org/2001/XMLSchema-instance" 

xmlns:xsd
="http://www.w3.org/2001/XMLSchema">

<soap:Body>

<! – the following is an xml document described in the service’s 

contract using XML schema. In this case SendTemperature may or may not 

be the name of the remote procedure being invoked by this message. 

Also, Collection may or may not be the name of the parameter. We know the 

structure of the xml document but We don’t know how the service 

is going to process it -- 
>

<SendTemperature xmlns="http://interop.webservices.fhso.ch/docLitWrapped">

<Collection>

<Temperature>

<Id>2</Id>

<Name>Station 1</Name>

<value>34.2</value>

</Temperature>

<Temperature>

<Id>56</Id>

<Name>Station 3</Name>

<value>23.6</value>

</Temperature>

</Collection>

</SendTemperature>

</soap:Body>

</soap:Envelope>

清单 10. SendTemperatureDocument/Literal 外覆样式中的WSDL消息.

下面就是该方法缺点与优点的总结:

优点:

    • 包含了所有Document/Literal样式的优点。
    • 操作名出现在SOAP消息中。

缺点:

    • 即使WSDL定义变得更加复杂,但仍然有不少缺点。
    • 如果你在web服务中重载了操作,你就不能使用该样式。

到现在为止,我们看到Document/Literal Document/Literal外覆样式相比于任何其它样式,带给我们许多的弹性和优点,但是仍存在一些有待解决的问题。

Document/Literal Document/Literal 外覆样式的局限性

假设,我们如清单11中显示的那样重载了操作。

public void SendTemperature (Temperature[] TempCollection){}

public void SendTemperature (Temperature[] TempCollection, int week){}

清单11. 重载 SendTemperature 方法.

在这种情况,就不可能使用Document/Literal外覆样式,即使WSDL规范允许有重载的方法。原因就是,当我们在一个WSDL文档中增加一个外覆样式时,你将需要一个跟操作相同名字的元素(请看清单9)。当我们想在XML Schema有两个同名称的元素时问题就出现了。因此,我们为了重载的操作的来个二选一,要么寻找非Ddocument/Literal外覆样式,要么一种RPC样式。

让我们看看我们怎么在Document/Literal样式中实现它,这儿在WSDL定义的schema 节为上述的两个web方法有了修改。

 

<types>

<s:schema elementFormDefault="qualified" 

   targetNamespace
="http://interop.webservices.fhso.ch/docLit">

<s:element name="Collection">

<s:complexType>

<s:sequence>

<s:element minOccurs="0" maxOccurs="unbounded" name="Temperature" 

   nillable
="true" type="s0:Temperature"/>

<s:element minOccurs="0" maxOccurs="1" name="week" type="s:int"/>

</s:sequence>

</s:complexType>

</s:element>

<s:complexType name="Temperature">

<s:sequence>

<s:element minOccurs="0" maxOccurs="1" name="Id" type="s:int"/>

<s:element minOccurs="0" maxOccurs="1" name="Name" type="s:string"/>

<s:element minOccurs="0" maxOccurs="1" name="value" type="s:double"/>

</s:sequence>

</s:complexType>

<s:element name="SendTemperatureResponse">

<s:complexType/>

</s:element>

</s:schema>

</types>

清单12. SendTemperatureWSDL定义的Schema 节作了更改

我们仅向集合中添加了另一个元素,所有其它的跟清单7中保持相似。有趣的是让我们看看用VS.NET wsdl.exe 实用工具生成的客户端代理。

 

Public void SendTemperature([System.Xml.Serialization.XmlElementAttribute("Protocol"

                IsNullable
=true)] Temperature[] Temperature, int week, 

                [System.Xml.Serialization.XmlIgnoreAttribute()] 
bool weekSpecified) {

this.Invoke("SendTemperature"new object[] {

   Temperature,

   week,

   weekSpecified});

}

清单13. 为重载操作SendTemperature生成的C#代理代码

注意到有另外一个名称为weekSpecifiedBoolean型参数被自动创建,现在客户端就能用两种方法调用这个重载操作的web方法,如果一个客户端调用的方法有week参数以及 weekSpecified 的值设为false时,我们调用的是清单11中的第一个方法,还有SOAP请求也跟清单10中的一种相同。

 

SendTemperature(Temperatue_Object,7,false);

 

另一方面客户端调用的方法weekSpecified 的值被设为true时,那么它引用在清单11中的重载方法,以及现在的SOAP请求看起来就像清单14的那样,以一个XML标签来传递week 参数。

 

SendTemperature(Temperature_Object,7,true);

 

<soap:Envelope 

xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 

xmlns:xsi
="http://www.w3.org/2001/XMLSchema-instance" 

xmlns:xsd
="http://www.w3.org/2001/XMLSchema">

<soap:Body>

<Collection xmlns="http://interop.webservices.fhso.ch/docLit">

<Temperatue>

<Id>2</Id>

<Name>Station 1</Name>

<value>34.2</value>

</Temperature>

<Temperature>

<Id>56</Id>

<Name>Station 3</Name>

<value>23.5</value>

</Temperature>

<week>7</week>

</Collection>

</soap:Body>

</soap:Envelope>

清单14. 第二个重载操作的SOAP消息形式

现在我们已经看到因Document/Literal 外覆样式引起的问题怎样通过使用标准的Document/Literal样式而巧妙地解决了。

结论

Document-centricRPC 样式的Web服务提供了非常不同的应用环境,Document样式的web服务更加适合于企业到企业在Internet上的交互,开发一个Document样式的web服务也许需要比RPC样式付出更多的努力。我们看到了Document/Literal 样式和Document/Literal 外覆样式相比于其它设计样式带给我们更多弹性和优点。任何时候,你不要对已经存在的RPC样式进行接口连接,document样式的益处通常价值大于对服务进行接口连接。如果你设计web服务的主要需求是互用性,协调工作,那么RPC/Encoded样式就十分气馁了。

WS-I Basic profile 1.0不提倡使用RPC/Encoded方法,推荐使用Document/Literal方法,还有RPC/Literal是惟一允许的RPC 样式的style/use组合。许多人都认为在将来的WSI-profile版本中会屏弃RPC/Literal样式

参考

 

posted on 2006-01-24 18:10  叶漂  阅读(3479)  评论(6编辑  收藏  举报