1. 程式人生 > >Web Services 中XML、SOAP和WSDL的一些必要知識

Web Services 中XML、SOAP和WSDL的一些必要知識

Web Services 是由xml來定義資料格式的,通過SOAP協議在各個系統平臺中傳輸,那麼接下來討論下SOAP和WSDL的各自作用。

SOAP和WSDL對Web Service、WCF進行深入瞭解的基礎,因此花一些時間去了解一下是很有必要的。

一、SOAP(Simple Object Access Protocol)
如果我們要呼叫遠端物件的方法,就必定要告訴對方,我們要呼叫的是一個什麼方法,以及這個方法的引數的值等等。然後對方把資料返回給我們。
這其中就涉及到兩個問題:1、資料如何在網路上傳輸。2、如何表示資料?用什麼格式去表示函式以及它的引數等等。
1、SOAP的傳輸協議
SOAP的傳輸協議使用的就是HTTP協議。只不過HTTP傳輸的內容是HTML文字,而SOAP協議傳輸的是SOAP的資料。看一下下面的例子:
這是一個HTTP請求(請求google的首頁)的內容:
GET / HTTP/1.1 Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/x-ms-application, application/x-ms-xbap, application/vnd.ms-xpsdocument, application/xaml+xml, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
Accept-Language: en-us
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; CIBA) chromeframe/4.0
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
Host: www.google.com
Cookie: PREF=ID=d8f9f1710bfa5f72:U=a5b3bec86b6433ef:NW=1:TM=1260238598:LM=1260241971:GM=1:S=q2agYsw3BsoOQMAs; NID=29=JgIGDDUx70IQTBVAnNEP_E9PLLKBI9STjzaBjgq1eWuDg-_jCgFpka59DrOC0aZKLbj4q77HU1VMKscXTP3OaseyTbv643c2XPe9dS7lsXDHAkAnS46vy-OU8XRqbmxJ; rememberme=true; SID=DQAAAH4AAABW7M4nVkTeOR7eJUmC1AJ4R6hYbmVewuy_uItLUTzZMUTpojdaHUExhPa_EPAkO9Ex1u3r7aPXZ5cj28xHnv2DbfRYf5AyaBcimciuOTITKSIkqn3QSpGDFkRS1Xn7EGzDpCV0V1xFlCu0erf_jfe_D6GOgC2P2S08jNdFS9Vpmw; HSID=AFEFTMA68EgNjkbil; __utmx=173272373.; __utmxx=173272373.

---------如果有Post的資料,這裡還會有Post的資料--------

這個是一個SOAP請求的內容:
POST /WebServices/WeatherWebService.asmx HTTP/1.1
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; MS Web Services Client Protocol 2.0.50727.3603)
Content-Type: text/xml; charset=utf-8
SOAPAction: "http://WebXml.com.cn/getSupportCity"
Host: www.webxml.com.cn
Content-Length: 348
Expect: 100-continue
Connection: Keep-Alive

<?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><getSupportCity xmlns="http://WebXml.com.cn/"><byProvinceName>廣東</byProvinceName></getSupportCity></soap:Body></soap:Envelope>

可以看到,一個SOAP請求其實就是一個HTTP請求,但為了表明內容是SOAP的資料,需要加入上面請求中紅色字的部分來以示區別。也就是說,如果請求頭中有SOAPAction這一段,那麼請求會被當作SOAP的內容來處理而不會當作HTML來解析。可以用上面指定SOAPAction頭來表示內容是SOAP的內容,也可以指定 Content-Type: application/soap+xml 來表示內容是SOAP的內容。SOAP請求中最後的那段XML資料,這個就是請求的具體內容,這個就是SOAP規定的請求的資料格式,下面再詳細對格式進行說明。

2、SOAP的資料格式
現在知道了SOAP是通過HTTP協議的POST方法來傳輸資料的,只不過是請求的Header中加了一些標誌來說明自己是一個SOAP請求。那麼資料的具體格式是怎麼規定的呢,我們把上面請求的XML資料展開看一下:

<?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>
<getSupportCity xmlns="http://WebXml.com.cn/">
<byProvinceName>廣東</byProvinceName>
</getSupportCity>
</soap:Body>
</soap:Envelope>
其中的<soap:Body>裡面的內容就是請求的內容,請求的方法為getSupportCity,該方法有一個名為byProvinceName的引數,引數的值為“廣東”這個字串。再看一下返回的內容:

HTTP/1.1 200 OK
Date: Mon, 14 Dec 2009 05:55:39 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50727
Cache-Control: private, max-age=0
Content-Type: text/xml; charset=utf-8
Content-Length: 1052

<?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><getSupportCityResponse xmlns="http://WebXml.com.cn/"><getSupportCityResult><string>廣州 (59287)</string><string>深圳 (59493)</string><string>潮州 (59312)</string><string>韶關 (59082)</string><string>湛江 (59658)</string><string>惠州 (59298)</string><string>清遠 (59280)</string><string>東莞 (59289)</string><string>江門 (59473)</string><string>茂名 (59659)</string><string>肇慶 (59278)</string><string>汕尾 (59501)</string><string>河源 (59293)</string><string>揭陽 (59315)</string><string>梅州 (59117)</string><string>中山 (59485)</string><string>德慶 (59269)</string><string>陽江 (59663)</string><string>雲浮 (59471)</string><string>珠海 (59488)</string><string>汕頭 (59316)</string><string>佛山 (59279)</string></getSupportCityResult></getSupportCityResponse></soap:Body></soap:Envelope>
返回的HTTP頭中並沒有標誌來表明是一個SOAP的響應,因為的確沒有必要,請求方傳送出的SOAP請求,返回的肯定是SOAP的響應。

一個典型的SOAP請求格式的結構如下:
<?xml version="1.0"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">

<soap:Header>
<m:Trans xmlns:m="http://www.w3schools.com/transaction/"
soap:mustUnderstand="1">234
</m:Trans>
</soap:Header>

<soap:Body>
<m:GetPrice xmlns:m="http://www.w3schools.com/prices">
<m:Item>Apples</m:Item>
</m:GetPrice>
</soap:Body>

</soap:Envelope>

下面逐個解釋裡面的元素:
a) Envelope
SOAP的請求內容必須以Envelope做為根節點。
xmlns:soap="http://www.w3.org/2001/12/soap-envelope",不能修改,否則會出錯。http://www.w3.org/2001/12/soap-envelope裡面有Envelope的schema的相關定義。有興趣的可以去這個連結的內容。
soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding",這個指定了資料元素的型別。

b) Header
這個是可選的,如果需要新增Header元素,那麼它必須是Envelope的第一個元素。
Header的內容並沒有嚴格的限制,我們可以自己新增一些和應用程式相關的內容,但是客戶端一定要記得處理這些Header元素,可以加上mustUnderstand強制進行處理。

c) Body
這個就是請求的主題內容了,請求什麼函式,引數是什麼型別等等都在這裡面指定。
用標籤表示一個函式,然後用子元素表示它的引數。

在呼叫中沒有指定引數和返回型別,這裡不需要指定,因為提供服務的一方自己已經規定好了資料型別,在呼叫時指定資料型別沒有任何意義。

二、WSDL(Web Services Description Language)
  WSDL是用來描述WebService的,它用XML的格式描述了WebService有哪些方法、引數型別、訪問路徑等等。我們要使用一個WebService肯定首先要獲取它的WSDL,在VS中新增一個Web 引用時,這些工作由開發環境幫我們做了,開發環境根據WSDL文件給Web Service生成了相應的代理類供我們使用。
下面是一個HelloWorld的WebService的服務端程式碼:
public class Service : System.Web.Services.WebService
{
public Service () {

//Uncomment the following line if using designed components
//InitializeComponent();
}

[WebMethod]
public DateTime HelloWorld(int i)
{
return DateTime.Now;
}
}
  其對應的WebService的WSDL文件如下:
1 <?xml version="1.0" encoding="utf-8"?>
2 <wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:tns="http://tempuri.org/" xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" targetNamespace="http://tempuri.org/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
3 <wsdl:types>
4 <s:schema elementFormDefault="qualified" targetNamespace="http://tempuri.org/">
5 <s:element name="HelloWorld">
6 <s:complexType>
7 <s:sequence>
8 <s:element minOccurs="1" maxOccurs="1" name="i" type="s:int" />
9 </s:sequence>
10 </s:complexType>
11 </s:element>
12 <s:element name="HelloWorldResponse">
13 <s:complexType>
14 <s:sequence>
15 <s:element minOccurs="1" maxOccurs="1" name="HelloWorldResult" type="s:dateTime" />
16 </s:sequence>
17 </s:complexType>
18 </s:element>
19 </s:schema>
20 </wsdl:types>
21 <wsdl:message name="HelloWorldSoapIn">
22 <wsdl:part name="parameters" element="tns:HelloWorld" />
23 </wsdl:message>
24 <wsdl:message name="HelloWorldSoapOut">
25 <wsdl:part name="parameters" element="tns:HelloWorldResponse" />
26 </wsdl:message>
27 <wsdl:portType name="ServiceSoap">
28 <wsdl:operation name="HelloWorld">
29 <wsdl:input message="tns:HelloWorldSoapIn" />
30 <wsdl:output message="tns:HelloWorldSoapOut" />
31 </wsdl:operation>
32 </wsdl:portType>
33 <wsdl:binding name="ServiceSoap" type="tns:ServiceSoap">
34 <soap:binding transport="http://schemas.xmlsoap.org/soap/http" />
35 <wsdl:operation name="HelloWorld">
36 <soap:operation soapAction="http://tempuri.org/HelloWorld" style="document" />
37 <wsdl:input>
38 <soap:body use="literal" />
39 </wsdl:input>
40 <wsdl:output>
41 <soap:body use="literal" />
42 </wsdl:output>
43 </wsdl:operation>
44 </wsdl:binding>
45 <wsdl:binding name="ServiceSoap12" type="tns:ServiceSoap">
46 <soap12:binding transport="http://schemas.xmlsoap.org/soap/http" />
47 <wsdl:operation name="HelloWorld">
48 <soap12:operation soapAction="http://tempuri.org/HelloWorld" style="document" />
49 <wsdl:input>
50 <soap12:body use="literal" />
51 </wsdl:input>
52 <wsdl:output>
53 <soap12:body use="literal" />
54 </wsdl:output>
55 </wsdl:operation>
56 </wsdl:binding>
57 <wsdl:service name="Service">
58 <wsdl:port name="ServiceSoap" binding="tns:ServiceSoap">
59 <soap:address location="http://localhost:2206/WebSite1/Service.asmx" />
60 </wsdl:port>
61 <wsdl:port name="ServiceSoap12" binding="tns:ServiceSoap12">
62 <soap12:address location="http://localhost:2206/WebSite1/Service.asmx" />
63 </wsdl:port>
64 </wsdl:service>
65 </wsdl:definitions>

一個WSDL文件由四部分組成:
1、types
  指定了WebService用到的所有資料型別,上面用到了兩種資料型別,int和datetime

2、message
  指明一個操作所用到的資料型別。
  HelloWorldSoapIn是指HelloWorld的輸入操作用到的資料型別,HelloWorldSoapOut是指HelloWorld的輸出操作用到的資料型別。二者的element元素指出了與types中對應到的具體型別。

3、portType
  指出了這個WebService所有支援的操作,就是說有哪些方法可供呼叫。
  這裡支援一個HelloWorld呼叫,它的輸入和輸出對應到HelloWorldSoapIn和HelloWorldSoapOut這個兩個資料型別。

4、binding
  soap12:binding元素的transport指明傳輸協議,這裡是http協議。
  operation 指明要暴露給外界呼叫的操作。
  use屬性指定輸入輸出的編碼方式,這裡沒有指定編碼。

5、services
  指定服務的一些資訊,主要是指定服務的訪問路徑。