元數據其實是服務終結點的描述,終結點由地址(Address)、綁定(Binding)和契約(Contract)經典的ABC三要素組成。認真閱讀過《WCF技術剖析(卷1)》的讀者相對會對這三要素的本質有一個深入的認識:地址決定了服務的位置並實現相應的尋址機制;契約描述了消息交換模式(Message Exchange Pattern: MEP)以及消息的結構(Schema);綁定則經過建立信道棧實現對消息的編碼、傳輸和基於某些特殊的功能(好比實現事務、可靠傳輸以及基於消息的安全)對消息做出的處理。 html
服務的消費者經過獲取服務端發佈的元數據,並在此基礎上重建終結點,才能取保請求:消息被髮送到準確的目標地址;採用服務端指望的消息交換模式和並生成服務端可以識別的消息結構;使用相匹配的消息編碼方式以確保服務端可以對接收到的消息進行正常解碼;使用一致的傳輸協議以實現消息的正常傳輸;對消息進行與服務端一致性的處理以確保對事務、可靠傳輸、消息安全等協議的實現。 安全
WCF是基於SOA構建的一個分佈式通訊平臺,而SOA一個重要的特性就是實現跨平臺的互操做。元數據是確保服務消費者正常調用目標服務(可能部署於異質平臺),因此元數據自己須要採用一種開放的標準來表示。目前,元數據具備三種比較典型的表示方式: 網絡
對跨平臺互操做的實現不只僅要求承載服務描述信息的元數據自己採用一種開放的標準或者規範來表示,甚至要求元數據交換(Metadata Exchange:MEX)一樣按照廠商共同遵照的規範來進行。在WS-*規範體系中,WS-Metadata Exchange(WS-MEX)爲元數據的交換進行了標準化的規範。WS-MetadataExchange(如下簡稱WS-MEX)規範了與終結點(這裏是廣義的Web服務終結點,與具體的技術無關)如何表示成一個WS-Transfer資源,並被嵌入到WS-Addressing終結點引用(Endpoint Reference)中,以及元數據如何被相應的Web服務終結點獲取。簡言之,WS-MEX是一個關於如何進行元數據交換的WS規範。WS-MEX和其餘的WS-*規範一塊兒,好比WSDL、WS-Addressing、WS-Transfer、WS—Policy等一塊兒組成了一個完整的描述Web服務元數據和元數據交換的規範體系,在正式介紹WS-MEX以前,先來大概瞭解一些其餘的這些輔助性WS-*規範。 數據結構
1、WS-Policy架構
一個Web服務(這裏指廣義的、與技術平臺無關的Web服務)除了實現經過服務契約定義的業務功能以外,爲了實現一些額外的功能(好比安全、事務和可靠傳輸等),還須要具備一些與業務無關的行爲(Behavior)和能力(Capability),咱們能夠將這些統稱爲Web服務的策略(Policy)。WS-Policy提供了一個基於XML的框架模型和語法用於描述Web服務的能力、要求和行爲屬性。 app
WS-Policy屬於WS-*體系中的一個基礎性規範,其規範自己不會被單獨使用,而是服務於其餘的WS規範(咱們通常稱這些爲Domain Specific規範,好比WS-Transaction、WS-Reliable Messaging和WS-Security等)提供一種統一的策略描述。 框架
W3C前後在2006年和2007年推出了兩個版本的WS-Policy規範,即WS-Policy 1.2和WS-Policy 1.5。在這裏,咱們僅僅是正對最新的WS-Policy版本(1.5)來簡單介紹一些一個完整的WS策略具備怎樣的結構,對於但願深刻了解WS-Policy的讀者,能夠經過後面的地址下載到W3C的官方文檔:http://www.w3.org/TR/ws-policy/。 分佈式
WS-Policy採用一個基於XML的策略表達式(Policy Expression)表示一個策略,在投入到對具體策略定義的介紹以前,咱們不妨先來看看一個典型的策略表達式的定義。下面XML片段表示的策略表達式來自於WS-Security,這是一個基於如何實現基於消息安全的WS規範。它體現的含義是:對消息的主題部分採用簽名仍是加密。post
1: (01)<wsp:Policy
2: xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"
3: xmlns:wsp="http://www.w3.org/ns/ws-policy" >
4: (02) <wsp:ExactlyOne>
5: (03) <wsp:All>
6: (04) <sp:SignedParts>
7: (05) <sp:Body/>
8: (06) </sp:SignedParts>
9: (07) </wsp:All>
10: (08) <wsp:All>
11: (09) <sp:EncryptedParts>
12: (10) <sp:Body/>
13: (11) </sp:EncryptedParts>
14: (12) </wsp:All>
15: (13) </wsp:ExactlyOne>
16: (14) </wsp:Policy>
上面這個XML採用一種標準的形式(WS-Policy還定義了一種簡寫的策略表示方式)定義一個策略,接下來咱們就此爲基礎介紹一個完整的策略表達式具備怎樣的結構。 網站
在一個基於Web服務的系統中,策略體現的對Web服務相關實體要求(Requirements)、能力(Capabilities)和特性(Characteristics)等行爲屬性的表示。WS-Policy經過斷言(Assertion)的形式來表示這些單一的行爲屬性,而後經過必定的規則將相關的策略斷言有機的組合在一塊兒,以實現對整個Web服務目標實體的完整描述。
按照WS-Policy 1.5的規定,全部的策略元素均定義在http://www.w3.org/ns/ws-policy命名空間下,一個完整策略經過一個基於XML的策略表達式描述。一、
一、策略表達式(Policy Expression)
一個策略表達式是一個XML信息集(XML InfoSet),描述了一個完整的策略。策略表達式具備兩個不一樣的表示形式:標準形式(Normal Form)和簡寫形式(Compact Form)。一個策略表達式是一個策略選擇項(Policy Alternative)的集合。咱們要求知足某個策略,意味着咱們需要知足該集合的至少一個策略選擇項。
二、策略選擇項(Policy Alterative)
通常狀況下,策略每每是承載一些確保服務正常調用(說得更加具體一點,就是確保Web服務終結點可以正常交互)的條件信息。服務的消費者在進行正常的服務消費以前,須要保證提供這些必備的前提條件。對於服務提供者來講,針對某個具體的應用場景的時候,會提供一到多個不一樣的選擇項。好比咱們上面給出的例子,在應用基於消息的安全策略的時候,根據不一樣安全級別的需求,能夠選擇對消息的主體部分進行簽名或者加密。
這些單一的選擇項被稱爲策略選擇項(Policy Alternative),對於上面給出的策略表達式,(03)-(07)和(08)-(12)定義兩個策略選擇項,表明對消息主體進行簽名仍是加密。一個策略選擇項由零到多個策略斷言經過相應的策略操做符組合在一塊兒。
三、策略斷言(Policy Assertion)
在WS-Policy規範下,Web服務實體某個單一的行爲屬性最終經過一個策略斷言表示。而一個策略斷言由一個好比的斷言類型(Assert Type)和一組可選的斷言參數(Assert Parameter)組成。斷言類型經過一個有效名稱(Qualified Name: QName)表示,即命名空間和本地名稱(Local Name)的組合。在定義了兩個策略斷言:(04)-(06)和(09)-(11),其斷言類型分別爲:sp:SignedParts和sp:EncryptedParts。
一個最簡單的策略斷言能夠僅僅由一個包含斷言類型的空XML元素構成,咱們也能夠爲這個XML元素添加用於輔助描述該斷言的XML屬性(Attribute)和XML子元素,咱們把這些策略輔助描述信息稱爲斷言參數。
一個策略斷言能夠很簡單(一個空XML元素),也能夠定義的很複雜,這取決於具體的策略描述對象。一個比較極端的策略斷言是:將一個完整的策略表達式做爲其子元素,咱們把這種狀況稱爲策略斷言嵌套(Policy Assetion Nesting)。嵌套的策略斷言的結構能夠經過下面的XML表示:
1: (01) <Assertion …>
2: (02) …
3: (03) ( <wsp:Policy …> … </wsp:Policy> )?
4: (04) …
5: (05) </Assertion>
四、策略操做符(Policy Operator)
一個策略選擇項又由零(也就是說能夠定義空的策略選擇項)到多個策略斷言經過必定的規則構成,在這裏對策略斷言的組合規則經過策略操做符來體現。策略操做符體現的是這樣一種含義:請求者採用怎樣的方式去知足構成策略選擇項的全部策略斷言,須要知足全部的斷言呢,仍是僅僅須要知足其中某一個?
WS-Policy定義了兩種主要的策略操做符(實際上Policy自己就屬於一個策略操做符)ExactlyOne和All。根據名稱咱們不難猜出,ExactlyOne表示僅僅須要知足斷言集合的某一個元素便可,而All意味着須要知足斷言集合中的全部元素。
此外,因爲wsp:ExactlyOne表示的是「知足其中之一」的意思,這和策略和策略選擇項之間體現的關係吻合,因此在標準形式體現的策略表達式中,全部的策略選擇項均納於wsp:ExactlyOne操做符之中。
圖1 策略表達式結構圖
整個策略表達式的結構,即策略、策略選擇項和策略斷言之間的關係,大致能夠經過圖1表示。關於WS-Policy中對策略表達式的規定,還一個其餘一些額外的內容,好比策略的識別(Policy Identifying)、策略簡寫形式(Compact Form)等,在這裏就再也不一一介紹了,有興趣的讀者能夠下載WS-Policy 1.5的官方文檔(http://www.w3.org/TR/ws-policy/)。
2、WS-Transfer
在Web服務的世界中,不少資源(Resource)均可以經過XML的形式來表示,並經過WS-Addressing規範的方式進行尋址。而WS-Transfer就是這樣的一個WS規範:規定如何採用基於SOAP的方式實現可尋址的(Addressable)Web服務資源的獲取、更新、刪除和建立。接下來對WS-Transfer的介紹,假設你對WS-Addressing和SOAP有了一個基本的瞭解。對這兩個規範不是很熟悉的讀者,能夠從W3C的網站上下載官方文檔。此外,在《WCF技術剖析(卷1)》的第2章和第6章對WS-Addressing 1.0和SOAP 1.2進行了歸納性的介紹。
雖然咱們能夠經過不少不一樣的方式(好比REST)對資源進行獲取和更新,WS-Transfer徹底創建在基於SOAP基礎上。WS-Transfer的主要內容集中在對4個基本資源操做上面:Get、Put、Delete和Create,分別實現對資源的獲取、更新、刪除和建立。W3C分別在2006年3月份和9月份前後推出了兩個版本的WS-Transfer,咱們接下來的介紹徹底基於最新版本的WS-Transfer,你能夠從後面的地址獲取正式的官方文檔:http://www.w3.org/Submission/WS-Transfer/。
因此基於WS-Transfer元素定義在http://schemas.xmlsoap.org/ws/2004/09/transfer命名空間下。接下來咱們着重對上述的4個資源進行介紹。
一、資源的獲取:Get
請求者創結基於Get操做的SOAP消息像目標地址發送請求以獲取相應的資源,這樣的請求消息必須具備以下的格式。
1: <s:Envelope …>
2: <s:Header …>
3: <wsa:Action>
4: http://schemas.xmlsoap.org/ws/2004/09/transfer/Get
5: </wsa:Action>
6: <wsa:MessageID>xs:anyURI</wsa:MessageID>
7: <wsa:To>xs:anyURI</wsa:To>
8: …
9: </s:Header>
10: <s:Body ...>
11: …
12: </s:Body>
13: </s:Envelope>
WS-Addressing報頭Action的值必須是http://schemas.xmlsoap.org/ws/2004/09/transfer/Get,消息的主體(Body)部分爲空。資源接受Get請求後,採用以下結構的SOAP消息進行回覆,Action報頭爲http://schemas.xmlsoap.org/ws/2004/09/transfer/GetResponse,表示資源的XML必須做爲消息主體的第一個子元素。
1: <s:Envelope …>
2: <s:Header …>
3: <wsa:Action>
4: http://schemas.xmlsoap.org/ws/2004/09/transfer/GetResponse
5: </wsa:Action>
6: <wsa:RelatesTo>xs:anyURI</wsa:RelatesTo>
7: <wsa:To>xs:anyURI</wsa:To>
8: …
9: </s:Header>
10: <s:Body …>
11: xs:any
12: …
13: </s:Body>
14: </s:Envelope>
二、資源的更新:Put
請求者建立基於Put操做的SOAP消息,提供新的資源內容向目標地址發送請求,以更新某個現有的資源。Put請求消息必須具備以下的格式:
1: <s:Envelope …>
2: <s:Header …>
3: <wsa:Action>
4: http://schemas.xmlsoap.org/ws/2004/09/transfer/Put
5: </wsa:Action>
6: <wsa:MessageID>xs:anyURI</wsa:MessageID>
7: <wsa:To>xs:anyURI</wsa:To>
8: …
9: </s:Header>
10: <s:Body…>
11: xs:any
12: ...
13: </s:Body>
14: </s:Envelope>
Put請求消息的Action報頭爲http://schemas.xmlsoap.org/ws/2004/09/transfer/Put,表示資源的XML必須做爲消息主體的第一個子元素。資源接受Put請求後,經過具備以下格式的SOAP回覆請求。回覆消息的Action報頭爲http://schemas.xmlsoap.org/ws/2004/09/transfer/PutResponse,如何徹底採用請求者提供的資源對現有的目標資源進行更新,那麼回覆消息的主體部分爲空,不然將更新後的資源以XML的形式置於回覆消息主體部分的第一個子元素中。
1: <s:Envelope …>
2: <s:Header …>
3: <wsa:Action>
4: http://schemas.xmlsoap.org/ws/2004/09/transfer/PutResponse
5: </wsa:Action>
6: <wsa:RelatesTo>xs:anyURI</wsa:RelatesTo>
7: <wsa:To>xs:anyURI</wsa:To>
8: …
9: </s:Header>
10: <s:Body …>
11: xs:any ?
12: </s:Body>
13: </s:Envelope>
三、資源的刪除:Delete
請求者建立基於Delelte操做的SOAP消息向目標地址發送請求,以刪除某個現有的資源。Delelte請求消息必須具備以下的格式:
1: <s:Envelope …>
2: <s:Header …>
3: <wsa:Action>
4: http://schemas.xmlsoap.org/ws/2004/09/transfer/Delete
5: </wsa:Action>
6: <wsa:MessageID>xs:anyURI</wsa:MessageID>
7: <wsa:To>xs:anyURI</wsa:To>
8: …
9: </s:Header>
10: <s:Body … />
11: </s:Envelope>
Delete請求消息的Action報頭爲http://schemas.xmlsoap.org/ws/2004/09/transfer/Delete,消息主體部分爲空。資源接受Delete請求後,經過具備以下格式的SOAP回覆請求。回覆消息的Action報頭爲http://schemas.xmlsoap.org/ws/2004/09/transfer/DeleteResponse,回覆消息的主體部分爲空。
四、資源的建立:Create
請求者建立基於Create操做的SOAP消息向目標地址發送請求,以建立一個新的資源。Create請求消息必須具備以下的格式:
1: <s:Envelope …>
2: <s:Header …>
3: <wsa:Action>
4: http://schemas.xmlsoap.org/ws/2004/09/transfer/Create
5: </wsa:Action>
6: <wsa:MessageID>xs:anyURI</wsa:MessageID>
7: <wsa:To>xs:anyURI</wsa:To>
8: …
9: </s:Header>
10: <s:Body …>
11: xs:any
12: ...
13: </s:Body>
14: </s:Envelope>
Create請求消息的Action報頭爲http://schemas.xmlsoap.org/ws/2004/09/transfer/Create,新的資源內容以XML的形式做爲消息主體部分的第一個子元素。資源工廠接受Create請求後,經過具備以下格式的SOAP回覆請求。回覆消息的Action報頭爲http://schemas.xmlsoap.org/ws/2004/09/transfer/CreateResponse,並將新建立資源的WS-Addressing的終結點引用(Endpoint Reference)做爲回覆消息主體部分的第一個子元素。若是,最終被更新的資源內容和請求者提供的不一致,本更新的資源內容須要做爲回覆消息主體部分的第二個子元素返回。
1: <s:Envelope …>
2: <s:Header …>
3: <wsa:Action>
4: http://schemas.xmlsoap.org/ws/2004/09/transfer/CreateResponse
5: </wsa:Action>
6: <wsa:RelatesTo>xs:anyURI</wsa:RelatesTo>
7: <wsa:To>xs:anyURI</wsa:To>
8: …
9: </s:Header>
10: <s:Body …>
11: <wxf:ResourceCreated>endpoint-reference</wxf:ResourceCreated>
12: xs:any?
13: </s:Body>
14: </s:Envelope>
3、 WSDL
WSDL,全稱Web服務描述語言(Web Service Description Language),是採用XML格式的形式對Web服務的描述。WSDL將一個Web服務定義成一組終結點的集合,而每個終結點包含一系列基於消息(Message)的操做(Operation)。這些抽象的操做和消息最終和相應的協議以及消息格式綁定。
雖然W3C在2007年6月份就正式出臺了WSDL 2.0版本,並將其做爲官方推薦,可是該版本並無獲得普遍的推廣,並無被主流的廠商徹底支持。現在,WCF徹底支持的仍是WSDL 1.1版本,因此接下來咱們將針對這個版本對WSDL做一個簡單的介紹,對於但願瞭解WSDL1.1的讀者能夠從後面的地址下載官方文檔:http://www.w3.org/TR/wsdl。就WSDL描述對象的性質,咱們大致能夠將全部WSDL的元素劃分爲如下兩類:
爲了有效地瞭解WSDL的結構,咱們首先來看看一段直接從官方文檔上拷貝出來的WSDL文檔:
1: <?xml version="1.0"?>
2: <definitions name="StockQuote" targetNamespace="http://example.com/stockquote.wsdl" xmlns:tns="http://example.com/stockquote.wsdl" xmlns:xsd1="http://example.com/stockquote.xsd" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns="http://schemas.xmlsoap.org/wsdl/">
3: <types>
4: <schema targetNamespace="http://example.com/stockquote.xsd" xmlns="http://www.w3.org/2000/10/XMLSchema">
5: <element name="TradePriceRequest">
6: <complexType>
7: <all>
8: <element name="tickerSymbol" type="string"/>
9: </all>
10: </complexType>
11: </element>
12: <element name="TradePrice">
13: <complexType>
14: <all>
15: <element name="price" type="float"/>
16: </all>
17: </complexType>
18: </element>
19: </schema>
20: </types>
21: <message name="GetLastTradePriceInput">
22: <part name="body" element="xsd1:TradePriceRequest"/>
23: </message>
24: <message name="GetLastTradePriceOutput">
25: <part name="body" element="xsd1:TradePrice"/>
26: </message>
27: <portType name="StockQuotePortType">
28: <operation name="GetLastTradePrice">
29: <input message="tns:GetLastTradePriceInput"/>
30: <output message="tns:GetLastTradePriceOutput"/>
31: </operation>
32: </portType>
33: <binding name="StockQuoteSoapBinding" type="tns:StockQuotePortType">
34: <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
35: <operation name="GetLastTradePrice">
36: <soap:operation soapAction="http://example.com/GetLastTradePrice"/>
37: <input>
38: <soap:body use="literal"/>
39: </input>
40: <output>
41: <soap:body use="literal"/>
42: </output>
43: </operation>
44: </binding>
45: <service name="StockQuoteService">
46: <documentation>My first service</documentation>
47: <port name="StockQuotePort" binding="tns:StockQuoteBinding">
48: <soap:address location="http://example.com/stockquote"/>
49: </port>
50: </service>
51: </definitions>
上面給出的是一個很標準的WSDL文檔,從中咱們能夠看出它由五個子元素構成:Type、Message、PortType、Binding和Service。這五大元素構成一個了一個完成得WSDL,如今能夠就對它們逐個進行介紹。
一、Types:經過XSD表示的數據類型的集合
WSDL並無屬於本身的數據類型定義規範,而是直接採用XSD做爲數據定義的語言。上面的WSDL文檔經過XSD定義了兩個XML元素,元素名稱分別爲TradePriceRequest和TradePrice,命名空間爲http://example.com/stockquote.xsd。從XSD的定義咱們不難看出,這兩個類型分別是字符串和浮點數類型。
1: <types>
2: <schema targetNamespace="http://example.com/stockquote.xsd" xmlns="http://www.w3.org/2000/10/XMLSchema">
3: <element name="TradePriceRequest">
4: <complexType>
5: <all>
6: <element name="tickerSymbol" type="string"/>
7: </all>
8: </complexType>
9: </element>
10: <element name="TradePrice">
11: <complexType>
12: <all>
13: <element name="price" type="float"/>
14: </all>
15: </complexType>
16: </element>
17: </schema>
18: </types>
二、Message: 通訊數據的載體
Web服務採用基於消息的通訊方式,因此消息是通訊數據的載體。WSDL的message元素用於定義全部定義終結點操做的消息的結構。WSDL的消息是一個具備惟一標識(經過Name屬性)的XML元素,一般利用Types結點中定義的數據類型來描述。上面的WSDL定義了兩個消息,名稱分別爲GetLastTradePriceInput和GetLastTradePriceOutput,消息主體部分的結構經過引用定義在Types結點中的XML元素的有效名稱(QName:命名空間+本地名稱)。
1: <message name="GetLastTradePriceInput">
2: <part name="body" element="xsd1:TradePriceRequest"/>
3: </message>
4: <message name="GetLastTradePriceOutput">
5: <part name="body" element="xsd1:TradePrice"/>
6: </message>
三、PortType:相關操做的集合
一個服務邏輯上有一系列關聯的操做組成,從消息交換的角度上講,操做進行關聯的消息按照相應的消息交換模式的有機組合。WSDL的PortType表示的就是這麼一個操做的集合,反映在XML結構上,就是一組operation元素的基本。每個operation XML元素表明一個單一的操做,它經過一個或者多個消息組合而成。消息的不一樣組合方式反映了操做採用的不一樣消息交換模式(MEP: Message Exchange Pattern)。上面給出的WSDL經過以下的XML片段定義了一個僅僅包含一個操做的PortType。
1: <portType name="StockQuotePortType">
2: <operation name="GetLastTradePrice">
3: <input message="tns:GetLastTradePriceInput"/>
4: <output message="tns:GetLastTradePriceOutput"/>
5: </operation>
6: </portType>
在《WCF技術剖析(卷1)》第4章對服務操做的介紹中,咱們說服務契約中的操做契約本質上就是定義了操做採用的消息交換模式,以及消息的格式。在這裏你會進一步獲得證明,實際上,當某個WCF服務經過WSDL的形式發佈出來,服務契約映射的部分就是PortType。WCF支持三種典型的消息交換模式:單工(One-way)請求回覆(Request-Reply)和雙工(Duplex)。實際上,雙工模式是由前面兩種模式組合而成,單工(One-way)和請求-回覆(Request-Reply)模式纔是基元消息交換模式。除了這兩種基元模式,WSDL還對另外兩種消息交換模式提供支持:懇請-回覆(Solicit-Response)和通知(Notification)模式。
PortType中的每個操做均由輸入(Input)和輸出(Output)消息的不一樣組合方式定義,而這種對輸入、輸出消息的不一樣組合就是對某種消息交換模式的反映。接下來,咱們站在服務端終結點的角度,來介紹上述的4中消息交換模式:
單工(One-way)
單工消息交換模式下,終結點僅僅是接收來自客戶端的請求。單向操做僅僅包含一個輸入消息,在WSDL中的表示以下:
1: <wsdl:definitions ... >
2: <wsdl:portType ... >*
3: <wsdl:operation name="nmtoken">
4: <wsdl:input name="nmtoken"? message="qname"/>
5: </wsdl:operation>
6: </wsdl:portType >
7: </wsdl:definitions>
請求-回覆(Request-Reply)
請求-回覆消息交換模式下,終結點接收來自客戶端的請求,並向發送匹配的回覆消息。請求-恢復操做經過輸入消息和輸出消息的有序組合表示,在WSDL中的表示以下:
1: <wsdl:definitions …>
2: <wsdl:portType …>*
3: <wsdl:operation name="nmtoken" parameterOrder="nmtokens">
4: <wsdl:input name="nmtoken"? message="qname"/>
5: <wsdl:output name="nmtoken"? message="qname"/>
6: <wsdl:fault name="nmtoken" message="qname"/>*
7: </wsdl:operation>
8: </wsdl:portType>
9: </wsdl:definitions>
懇請-回覆(Solicit-Response)
在懇請-回覆消息交換模式下,終結點先向客戶端到發送請求,並接收來自客戶端的回覆,這和請求-回覆模式正好相反。懇請-回覆操做由輸出消息和輸入消息的有序組合表示,在WSDL中的表示以下:
1: <wsdl:definitions …>
2: <wsdl:portType …>*
3: <wsdl:operation name="nmtoken" parameterOrder="nmtokens">
4: <wsdl:output name="nmtoken"? message="qname"/>
5: <wsdl:input name="nmtoken"? message="qname"/>
6: <wsdl:fault name="nmtoken" message="qname"/>*
7: </wsdl:operation>
8: </wsdl:portType>
9: </wsdl:definitions>
通知(Notification):
在通知消息交換模式下,終結點僅僅向客戶端發送請求,這和單向模式正好相反。通知操做由單一的輸出消息組成,在WSDL中的表示以下:
1: <wsdl:definitions …>
2: <wsdl:portType …> *
3: <wsdl:operation name="nmtoken">
4: <wsdl:output name="nmtoken"? message="qname"/>
5: </wsdl:operation>
6: </wsdl:portType>
7: </wsdl:definitions>
注:對於請求-回覆和懇請-回覆消息交換模式來講,雙方除了進行正常的消息交換以外,當錯誤發生,須要將錯誤信息封裝成消息發送給對方。因此,這兩種類類型的操做除了輸出消息和輸入消息的描述以外,還具備錯誤消息的描述。錯誤消息在操做中經過<wsdl:fault/〉表示。
四、Bindings:消息、操做與協議、格式的綁定
上面介紹WSDL的三個元素主要從抽象的角度對數據類型、消息和操做進行描述,要建立服務於具體消息交換場景的終結點,還須要將這需抽象的描述和具體的消息格式(Format)和網絡協議綁定,好比SOAP、HTTP-GET和MIME等。
在這裏,咱們頗有必要強調「終結點」,本節咱們提到的終結點在大部分場景中都是指與技術無關的、用於進行消息交換的「端口」。而咱們WCF中提到的終結點,能夠當作是這樣一個通用的終結點在具技術平臺中的實現。WCF的終結點由地址、綁定和契約構成,結合WSDL咱們不難看出,Type、Message和PortType是對契約的描述。而綁定,就其語言和功能上講,就是實現了抽象的描述和具體的協議(網絡傳輸協議、SOAP和WS-*規範等)之間的綁定。在WSDL中,Bindings元素具備同樣的功能。
在WSDL中,咱們能夠經過不少綁定擴展實現與某種協議的綁定,而最爲常見的是基於SOAP 1.1和SOAP 1.2的綁定。上面給出的WSDL中定義了一個典型的基於SOAP 1.1的綁定(SOAP 1.1和SOAP 1.2綁定的命名空間分別爲http://schemas.xmlsoap.org/wsdl/soap/和http://schemas.xmlsoap.org/wsdl/soap12/)。
1: <binding name="StockQuoteSoapBinding" type="tns:StockQuotePortType">
2: <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
3: <operation name="GetLastTradePrice">
4: <soap:operation soapAction="http://example.com/GetLastTradePrice"/>
5: <input>
6: <soap:body use="literal"/>
7: </input>
8: <output>
9: <soap:body use="literal"/>
10: </output>
11: </operation>
12: </binding>
以上面這個SOAP綁定爲例,一個綁定經過name屬性(name="StockQuoteSoapBinding")定義其惟一標識,並經過type屬性和定義個PortType(type="tns:StockQuotePortType")進行關聯。該SOAP綁定定義了消息採用的風格(style="document",另一個選項是「rpc」)和傳輸協議(transport="http://schemas.xmlsoap.org/soap/http")。在操做級別,定義了操做反映在SOAP Action報頭的值(soapAction="http://example.com/GetLastTradePrice"),以及輸入和輸出消息的主體部分採用的編碼方式(use="literal")。
五、Service:相關終結點的集合
因爲一個Web服務最終以終結點的方式暴露出來,因此WSDL最終體如今對終結點集合的描述,這裏介紹的WSDL最後一個元素<Service/>本質上就是對基於該Web服務的一組相關終結點的定義。咱們照例將上面給出的WSDL的Service相關部分提取出來,根據具體的例子分析Service結點應有的結構。
1: <service name="StockQuoteService">
2: <documentation>My first service</documentation>
3: <port name="StockQuotePort" binding="tns:StockQuoteBinding">
4: <soap:address location="http://example.com/stockquote"/>
5: </port>
6: </service>
<Service>經過name屬性(name="StockQuoteService")定義了服務的惟一標識。該節點具備一個可選的<documentation>元素,能夠經過單純的文本或者XML爲該服務定義一些可讀的說明性的描述。<Service>結點最重要的就是一組<port>元素,而每個port即表明着一個終結點。每一個具備一個name屬性定義終結點的名稱,經過binding屬性引用相應的定義得binding。並經過相應的綁定擴展定義終結點的地址,在這裏終結點的地址經過SOAP綁定定義(<soap:address location="http://example.com/stockquote"/>)。
圖2反映了WSDL5個元素之間的關係。對於表示一個終結點對象<port>元素來講,它具備一個地址(Address)和關聯着一個綁定(Binding),而綁定對象關聯着一個PortType。而一個PortType實際上對應的着WCF中的契約(Contract)。因此,WCF下的終結點由地址、綁定和契約三要素組成在這裏也獲得進一步的反映,實際上,WCF自己就是按照WS開放標準設計的。
圖2 WSDL5個元素之間的引用關係
WCF的元數據結構體系構建在一個開放的標準之上,這個標準就是WS-Metadata Exchange,簡稱WS-MEX。WS-MEX是WS-*你們庭中的一名重要成員,最新的版本是1.1,但願全面瞭解WS-MEX 1.1規範的讀者能夠從後面的地址下載官方文檔:http://specs.xmlsoap.org/ws/2004/09/mex/WS-MetadataExchange.pdf。規範瞭如何將基於Web終結點的元數據表示成一個WS-Transfer資源;如何將元數據內嵌於WS-Addressing的終結點引用(Endpoint Reference)中;以及如何獲取某個Web服務終結點的元數據。WS-MEX主要的目的在規範元數據的獲取,它提供了以下兩種不一樣的方式去獲取Web服務終結點的元數據:WS-Transfer Get和Get Metadata。此外,基於WS-MEX的元素定義在http://schemas.xmlsoap.org/ws/2004/09/mex命名空間下。
一、經過WS-Transfer GET操做獲取元數據
我之因此在正式介紹WS-MEX以前會先對WS-Transfer做一個簡單的討論,使由於採用WS-Transfer的Get操做是元數據的主要獲取方式之一。經過前面的介紹,咱們知道了WS-Transfer旨在規範如何獲取、更新、刪除和建立Web服務資源。元數據自己就能夠做爲一種典型的Web服務資源,那麼採用WS-Transfer無疑是一種最直接的選擇。
元數據的提供者將元數據做爲一種Web服務資源經過一個基於WS-Transfer的終結點暴露出來,請求者向該終結點發送WS-Transfer Get請求,以回覆消息的形式得到所需的元數據。下面就是一個典型的基於SOAP 1.1的WS-Transfer Get請求消息,請求的目標地址就是元數據資源對應的終結點。
1: <s11:Envelope xmlns:s11="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa10="http://www.w3.org/2005/08/addressing">
2: <s11:Header>
3: <wsa10:Action>http://schemas.xmlsoap.org/ws/2004/09/transfer/Get</wsa10:Action>
4: <wsa10:To>http://services.example.org/stockquote/metadata</wsa10:To>
5: <wsa10:ReplyTo>
6: <wsa10:Address>http://client.example.org</wsa10:Address>
7: </wsa10:ReplyTo>
8: <wsa10:MessageID>urn:uuid:1cec121a-82fe-41da-87e1-3b23f254f128</wsa10:MessageID>
9: </s11:Header>
10: <s11:Body />
11: </s11:Envelope>
針對上面一個基於WS-Transfer Get操做的元數據請求,可能會獲得以下一個標準的WS-Transfer Get回覆消息,請求的元數據被置於SOAP消息的主體部分。
1: <s11:Envelope xmlns:s11="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa10="http://www.w3.org/2005/08/addressing" xmlns:mex="http://schemas.xmlsoap.org/ws/2004/09/mex" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
2: <s11:Header>
3: <wsa10:Action> http://schemas.xmlsoap.org/ws/2004/09/transfer/GetResponse</wsa10:Action>
4: <wsa10:To>http://client.example.org</wsa10:To>
5: <wsa10:RelatesTo>urn:uuid:1cec121a-82fe-41da-87e1-3b23f254f128</wsa10:RelatesTo>
6: </s11:Header>
7: <s11:Body>
8: <mex:Metadata>
9: <mex:MetadataSection Dialect="http://schemas.xmlsoap.org/wsdl/">
10: <wsdl:definitions name="StockQuote" ...>
11: ...
12: </wsdl:definitions>
13: </mex:MetadataSection>
14: <mex:MetadataSection Dialect="http://www.w3.org/2001/XMLSchema" Identifier="http://services.example.org/stockquote/schemas">
15: <mex:Location>http://services.example.org/stockquote/schemas</mex:Location>
16: </mex:MetadataSection>
17: <mex:MetadataSection Dialect="http://schemas.xmlsoap.org/ws/2004/09/policy" Identifier="http://services.example.org/stockquote/policy">
18: <mex:MetadataReference>
19: <wsa10:Address>http://services.example.org/stockquote/policy</wsa10:Address>
20: </mex:MetadataReference>
21: </mex:MetadataSection>
22: </mex:Metadata>
23: </s11:Body>
24: </s11:Envelope>
從上面提供的包含元數據的SOAP消息中,咱們能夠看到:全部的元數據均包含在<Metadata>結點中。<Metadata>結點其實是一個<MetadataSection>元素的集合,具體的元數據定一個在相應的<MetadataSection>結點下,元數據的表現形式經過Dialect屬性定義。經過Dialect表示的元數據表示形式被稱爲元數據方言。
元數據方言(Dialect)
在本章開始的時候,咱們就談到Web服務終結點元數據具備三種典型的表現形式:WSDL、XSD和WS-Policy。在看看咱們上面給出的包含元數據的SOAP消息中,<Metadata>結點下三個<MetadataSection>分別就對應這三種形式的元數據。第一個<MetadataSection>經過內聯的方式直接嵌入一個WSDL文檔;第二個<MetadataSection>以地址的方式指定了一個XML Schema;第三個<MetadataSection>以終結點引用的方式指定了一個WS-Policy策略。<MetadataSection>的Dialect以一個決定地址的形式指明瞭元數據體現的形式,即元數據方言(Dialect)。圖3展示了Metadadata、MetadataSection以及這三種典型元數據方言之間的關係。在WS-MEX中爲如下5種方言定義了相應的URI:
注:WS-Policy Attachment是另一份WS規範,用於如何將WS-Policy中定義的策略和具體的WS規範(Domain-Specific WS Specification)進行關聯。MEX表明通常意義的元數據,它包含基於某種具體方言的元數據。
圖3 Metata、MetadataSection與三種典型的元數據表現形式
經過WS-Transfer Get的方式獲取Web服務終結點的元數據的前提是直接將元數據自己做爲Web服務資源。可是對於某些特殊的場景,這種方式不不太適合。好比,多個元數據資源關聯到同一個元數據終結點,但願經過向該終結點發送請求獲取全部相關的元數據;並且,並非在任何狀況下都能將終結點的元數據做爲一個能夠被尋址(基於WS-Addressing)的Web服務資源。爲了在這些場景中解決元數據的獲取,WS-MEX提出了另外一種替換的元數據獲取方式:Get Metadata。Get Metadata操做請求的SOAP消息具備以下的結構要求(?表示0或1個前置元素):
1: [action]
2: http://schemas.xmlsoap.org/ws/2004/09/mex/GetMetadata/Request
3: [Body]
4: <mex:GetMetadata ...>
5: (<mex:Dialect>xs:anyURI</mex:Dialect>
6: (<mex:Identifier>xs:anyURI</mex:Identifier>)?
7: )?
8: </mex:GetMetadata>
當服務終結點接受了Get Metadata請求後,生成相應的回覆消息並將元數據置於消息的主體部分。Get Metadata回覆消息具備以下的結構要求:
1: [action]
2: http://schemas.xmlsoap.org/ws/2004/09/mex/GetMetadata/Response
3: [Body]
4: <mex:Metadata ...>
5: ...
6: </mex:Metadata>