|
SoapRpcMethod SoapRpcService设计 XML Web services 时首先要作出的决定之一就是您要如何对 SOAP 请求中的 XML 进行编码。明确地说,您是要 XML 文档严格遵循 XSD 架构还是要遵循 SOAP 规范第 5 节和第 7 节中概述的格式设置规则?SOAP 规范第 5 节和第 7 节中的格式设置规则考虑到了变体。这样,使用 SOAP 编码规则的 SOAP 请求的接收方必须处理所有可能的变体。通过定义 XML Web services 方法的 XSD 架构,可以具体地定义 SOAP 请求中需要发送的确切内容。使用 ASP.NET 创建的 XML Web services 默认为使用基于架构传递的文档。
因为 XML Web services 方法的参数可以组成 SOAP 请求或响应中传递的大部分数据,所以参数映射到 XML 元素的方式决定了 XML 文档的外观。Web 服务描述语言 (WSDL) 定义了两种参数格式设置样式:Encoded 和 Literal。Encoded 是指使用 SOAP 规范第 5 节中概述的 SOAP 编码对参数进行格式设置。Literal 是指使用每个参数预定义的 XSD 架构将参数映射到 XML 元素。使用 XML Web services 客户端,您可以选择如何将参数映射到 XML 元素以匹配 XML Web services 需要的形式。使用 ASP.NET 创建的 XML Web services 支持 Literal 和 Encoded 两种参数格式设置样式。该支持根据 XML Web services 方法格式设置选择有所变化。
请注意,虽然 ASP.NET 提供了一个广泛的结构用来控制 XML 格式设置的方式,但是并不保证参数序列化的顺序。
我们可以写一个WebService例子来说明这一点:
testSoapParam.asmx:
<%@ WebService Language="C#" Class="testEncoded" %>
using System;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Web.Services.Description;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
using System.Data;
public class testEncoded : WebService {
[ SoapDocumentMethod(Use=SoapBindingUse.Encoded,ParameterStyle=SoapParameterStyle.Bare) ] //参数风格为:Encoded 并且是Bare
[WebMethod()]
public struct1 testStructBareEncode(struct1 a){
return a;
}
[ SoapDocumentMethod(Use=SoapBindingUse.Encoded) ]// 参数风格为:Encoded
[WebMethod()]
public struct1 testStructEncoded(struct1 a){
return a;
}
[ SoapDocumentMethod(Use=SoapBindingUse.Literal) ]//参数风格为:Literal
[WebMethod()]
public struct1 testStructLiteral(struct1 a){
return a;
}
[ SoapDocumentMethod(ParameterStyle=SoapParameterStyle.Bare) ]// 参数风格为:Bare
[WebMethod()]
public struct1 testStructBare(struct1 ddd){
return ddd;
}
}
public class struct1{
public int i=1;
public string j="ok";
public struct2 s2;
private struct2 temp;
public struct2 s4{
get{
return temp;
}
set{
temp=value;
}
}
}
public class struct2{
public String sField;
}
当我们运行客户端代理请求SOAP协议时,我们可以发现不同的参数风格有很大的区别,如使用Literal(默认)和Default时,SOAP协议客户端传输给服务端的XML内容为:
<?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>
<testStructLiteral xmlns="http://tempuri.org/">
<a>//参数名字
<i>int</i>
<j>string</j>
<s2>
<sField>string</sField>
</s2>
<s4>
<sField>string</sField>
</s4>
</a>
</testStructLiteral>
</soap:Body>
</soap:Envelope>
而使用Encoded时, SOAP协议客户端传输给服务端的XML内容为:
<?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:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://tempuri.org/" xmlns:types="http://tempuri.org/encodedTypes" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<types:testStructEncoded xsi:type="types:testStructEncoded">
<a href="#id1" /> //a 为参数名,id 号指出该对象是复杂类型,并为链路
</types:testStructEncoded>
<types:struct1 id="id1" xsi:type="types:struct1">
<i xsi:type="xsd:int">int</i>
<j xsi:type="xsd:string">string</j>
<s2 href="#id2" />
<s4 href="#id3" />
</types:struct1>
<types:struct2 id="id2" xsi:type="types:struct2">
<sField xsi:type="xsd:string">string</sField>
</types:struct2>
<types:struct2 id="id3" xsi:type="types:struct2">
<sField xsi:type="xsd:string">string</sField>
</types:struct2>
</soap:Body>
</soap:Envelope>
我们可以发现Encoded时,SOAP协议把对象和数组作为复杂类型同其他区分开来,并明确的指明每一个类型的名字。
如果是设置为Bare, SOAP协议客户端传输给服务端的XML内容为:
<?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>
<ddd xmlns="http://tempuri.org/"> //dd 为参数名
<i>int</i>
<j>string</j>
<s2>
<sField>string</sField>
</s2>
<s4>
<sField>string</sField>
</s4>
</ddd>
</soap:Body>
</soap:Envelope>
我们将它与上面(如果不设置Bare,默认为wrapped)进行比较可以发现它少了一层<testStructLiteral xmlns="http://tempuri.org/">。
而如果我们将Encoded和Bare一起来控制参数时,传输內容变成:
<?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:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://tempuri.org/" xmlns:types="http://tempuri.org/encodedTypes" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<types:struct1 xsi:type="types:struct1"> //第一个参数
<i xsi:type="xsd:int">int</i>
<j xsi:type="xsd:string">string</j>
<s2 href="#id1" />
<s4 href="#id2" />
</types:struct1>
<types:struct2 id="id1" xsi:type="types:struct2">
<sField xsi:type="xsd:string">string</sField>
</types:struct2>
<types:struct2 id="id2" xsi:type="types:struct2">
<sField xsi:type="xsd:string">string</sField>
</types:struct2>
</soap:Body>
</soap:Envelope>
我们可以发现不仅少一层,而且id号也变了。
我们不仅可以改变SOAP协议参数传输的框架,也可以改变具体每一个元素的值,如:[XmlElement()]可以指定元素的名字和名字空间(namespace),如果指定了([ return: XmlElement("ReturnValueElement",IsNullable=false)] 和 [XmlElement("MyAddressElement")),则传输的內容变成:
<?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>
<testStructSer xmlns="http://tempuri.org/">
<MyAddressElement>//指定的元素名字。
<i>int</i>
<j>string</j>
<s2>
<sField>string</sField>
</s2>
<s4>
<sField>string</sField>
</s4>
</MyAddressElement>
</testStructSer>
</soap:Body>
</soap:Envelope>
总之,我们可以根据XML的序列化来控制SOAP消息生成XML內容的形式。
SOAP的內容是很灵活的,这也体现了SOAP协议的兼容性及可扩充性,随着技术的发展,SOAP协议将不断完善,并可以将 SOAP 与任何能够传输 SOAP 信封的传输协议或机制(包括 SMTP、FTP 甚至软盘)结合在一起使用。
|