SOAP编码格式是Web services的客户端和服务端在发送SOAP请求和响应消息的时候都必须遵守的一种消息编码协定,这是为了方便进行基于远程过程调用(RPC)的通讯而产生的,因为不同的消息编码协定对应着SOAP消息与调用(或返回)对象之间不同的转换方式。编码格式有两类:对整个消息体(方法)的编码和对方法参数的编码
l 对整个SOAP消息体(Body)中的数据有两种格式设置方式:Document、RPC
l 对Body元素中方法的参数进行格式设置也有两种方式:Literal、Encoded
这些编码方式可以有选择的组合使用,以作用于客户端和服务端之间SOAP请求和响应消息的编码。具体实现方式就是在服务端Web services方法或其在客户端代理类中对应的方法前引入需要的属性。下面这张表介绍了每种编码格式组合的详细信息和SOAP消息样例(只以请求消息为例)。
| 整个 SOAP Body格式设置 | ||
Document 基于WSDL中对应方法的XML SCHEMA对整个方法(即消息体)进行编码 | RPC 基于SOAP规范第7节RPC编码规则对整个方法(即消息体)进行编码 | ||
参数格式设置 | Literal 基于WSDL中每个参数的XML SCHEMA对参数进行编码 | l 可使用的属性: [SoapDocumentService] 为整个Web services 指定默认的方法格式设置,置于[Webservice]属性之前 [SoapDocumentMethod] 为指定的Web Method设置方法格式,置于[Webmethod]属性之前或之后 l 上述属性使用的属性项: Use= 注:ASP.NET中默认的参数编码格式为Literal l 应用举例: 1)处理简单数据类型 见应用例1 2)处理复杂数据类型 见应用例2 l SOAP消息举例: 1)处理简单数据类型 见消息例1 2)处理复杂数据类型 见消息例2 | 不支持Literal参数编码格式 |
Encoded 基于SOAP规范第5节数据类型编码规则对参数进行编码 | l 可使用的属性: [SoapDocumentService] 为整个Web services指定默认的方法格式设置,置于[Webservice]属性之前 [SoapDocumentMethod] 为指定的Web Method设置方法格式,置于[Webmethod]属性之前或之后 l 上述属性使用的属性项: Use= l 应用举例: 1)处理简单数据类型 见应用例3 2)处理复杂数据类型 见应用例4 l SOAP消息举例: 1)处理简单数据类型 见消息例3 2)处理复杂数据类型 见消息例4 | l 可使用的属性: [SoapRpcService] 为整个Web services 指定默认的方法格式设置,置于[Webservice]属性之前 [SoapRpcMethod] 为指定的Web Method设置方法格式,置于[Webmethod]属性之前或之后 l 上述属性使用的属性项: 以上属性只支持 Encoded 参数格式,因此不具有Use 属性项 l 应用举例: 1)处理简单数据类型 见应用例5 2)处理复杂数据类型 见应用例6 l SOAP消息举例: 1)处理简单数据类型 见消息例5 2)处理复杂数据类型 见消息例6 |
注:以下例子中Address的定义如下:
public Class Address
{
Public String City;
Public String Street;
Public String Zip;
}
[ 应用例1 ]
[SoapDocumentMethod
("http://www.abedon.net/DocumentEncoded",RequestNamespace="http://www.abedon.net",ResponseNamespace="http://www.abedon.net",Use=SoapBindingUse.Literal
)]
public int Add(int a, int b){…}
[ 应用例2 ]
[SoapDocumentMethod
("http://www.abedon.net/DocumentEncoded",RequestNamespace="http://www.abedon.net",ResponseNamespace="http://www.abedon.net",Use=SoapBindingUse.Literal
)]
public string PostInfo(Address addr, bool usezip) {…}
[ 消息例1 ]
<?xml version="1.0" encoding="utf-8"?>
<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>
<Add xmlns="http://www.abedon.net">
<a>1</a>
<b>2</b>
</Add>
</soap:Body>
</soap:Envelope>
[ 消息例2 ]
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<PostInfo xmlns="http://www.abedon.net">
<addr>
<Street>aaa</Street>
<City>bbb</City>
<Zip>123456</Zip>
</addr>
<useZip>True</useZip>
</PostInfo>
</soap:Body>
</soap:Envelope>
[ 应用例3 ]
[SoapDocumentMethod
("http://www.abedon.net/DocumentEncoded",RequestNamespace="http://www.abedon.net",ResponseNamespace="http://www.abedon.net",Use=SoapBindingUse.
Encoded)]
public int Add(int a, int b){…}
[ 应用例4 ]
[SoapDocumentMethod
("http://www.abedon.net/DocumentEncoded",RequestNamespace="http://www.abedon.net",ResponseNamespace="http://www.abedon.net",Use=SoapBindingUse.
Encoded)]
public string PostInfo(Address addr, bool usezip) {…}
[ 消息例3 ]
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://tempuri.org/" xmlns:types="http://tempuri.org/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/">
<q1:Add xmlns:q1="http://www.abedon.net">
<a xsi:type="xsd:int">1</a>
<b xsi:type="xsd:int">2</b>
</q1:Add>
</soap:Body>
</soap:Envelope>
[ 消息例4 ]
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://tempuri.org/" xmlns:types="http://tempuri.org/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/">
<q1:PostInfo xmlns:q1="http://www.abedon.net">
<addr href="#id1" />
<usezip xsi:type="xsd:boolean">true</usezip>
</q1:PostInfo>
<types:Address id="id1" xsi:type="types:Address">
<City xsi:type="xsd:string">aaa</City>
<Street xsi:type="xsd:string">bbb</Street>
<Zip xsi:type="xsd:string">123456</Zip>
</types:Address>
</soap:Body>
</soap:Envelope>
[ 应用例5 ]
[SoapRpcMethod
("http://www.abedon.net/DocumentEncoded",RequestNamespace="http://www.abedon.net",ResponseNamespace="http://www.abedon.net")]
public int Add(int a, int b){…}
[ 应用例6 ]
[SoapRpcMethod
("http://www.abedon.net/DocumentEncoded",RequestNamespace="http://www.abedon.net",ResponseNamespace="http://www.abedon.net")]
public string PostInfo(Address addr, bool usezip) {…}
[ 消息例5 ]
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://tempuri.org/" xmlns:types="http://tempuri.org/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/">
<q1:Add xmlns:q1="http://www.abedon.net">
<a xsi:type="xsd:int">1</a>
<b xsi:type="xsd:int">2</b>
</q1:Add>
</soap:Body>
</soap:Envelope>
[ 消息例6 ]
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://tempuri.org/" xmlns:types="http://tempuri.org/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/">
<q1:PostInfo xmlns:q1="http://www.abedon.net">
<addr href="#id1" />
<usezip xsi:type="xsd:boolean">true</usezip>
</q1:PostInfo>
<types:Address id="id1" xsi:type="types:Address">
<City xsi:type="xsd:string">aaa</City>
<Street xsi:type="xsd:string">bbb</Street>
<Zip xsi:type="xsd:string">123456</Zip>
</types:Address>
</soap:Body>
</soap:Envelope>
另外,在文档样式的SOAP中还可通过指定SoapDocumentService或者SoapDocumentMethod属性的ParameterStyle属性项的值为Bare来使用空参数,此时请求和响应的数据紧跟在Body元素后面,下面是个例子:
l 应用举例:
[SoapDocumentMethod
(Use=SoapBindingUse.
Encoded,ParameterStyle=SoapParameterStyle.Bare)]
public int Add(int a, int b) {…}
l SOAP消息举例:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://tempuri.org/" xmlns:types="http://tempuri.org/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/">
<xsd:int xsi:type="xsd:int">1</xsd:int>
<xsd:int xsi:type="xsd:int">2</xsd:int>
</soap:Body>
</soap:Envelope>
// 可以看到Add方法元素不见了,包含参数的元素名(原来是a和b。如果使用Literal格式编码参数,则元素名保持不变,还是a和b)也变了,而且参数紧跟在Body元素后面。
另外,如果对Web services应用了SoapDocumentService属性,则ParameterStyle=SoapParameterStyle.Default
这条语句用来指定参数编码风格使用
Web services的默认值,这个默认值可以通过SoapDocumentService属性来设置;如果没有对Web services应用该属性,则ParameterStyle
的
默认值自动设为Wrapped,即参数被封装在 Body 元素之后的单个XML元素(即方法元素)中,这一点与Bare(没有方法元素)刚好相反。一般来说Wrapped这个参数用不上,因为它是默认值。
理论上文档(Document)样式的SOAP消息体(Body)内可以包含任何有效的XML文档,它可以通过Schema进行定义(Schema可能来自WSDL),这样Web Services可以接收或返回一个XML文档,然后根据Schema定义对文档进行并行化(Deserialize)操作,得到需要的对象,同样,编码消息时也是基于该Schema定义。而RPC风格的SOAP消息是根据SOAP规范第5节和第7节的编码规则来编码,遵循该规范的Web Services的服务端和客户端都知道如何按此规则进行串行和并行化操作,以便编码消息以及获取数据。
以上是对SoapDocumentService、SoapDocumentMethod、SoapRpcService和SoapRpcMethod四个属性与自定义SOAP消息相关的主要应用的讲解。SOAP的Encoding部分就介绍到这里,实际上从上面的一些例子不难看出,目前SOAP规范中对于编码格式的规定还很不完善,存在一些问题,不过我相信在SOAP规范的后续版本中这些问题能够得到妥善解决。如果您还需要更加深入地剖析编码格式对SOAP消息更多更具体的影响,可以利用第四部分讲述的SOAP扩展的一个具体应用——日志扩展来跟踪和分析由不同的编码格式产生的包含不同数据类型的各种SOAP消息。