SOAP和WSDL的一些必要知識
http://www.cnblogs.com/JeffreySun/archive/2009/12/14/1623766.html
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
可以看到,一個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 OKDate: 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的服務端程式碼:
publicclass 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
指定服務的一些資訊,主要是指定服務的訪問路徑。