填寫消息地址
現在我們已經看過了與消息交互的實體,詳細剖析了消息結構,然後看了一 下WCF 提供了幾個消息編碼器,現在我們來看一下如何在詳細發送的時候表示我 們要發送的目的地。畢竟,除非能發送給接受者,否則消息等於是毫無用處。和 郵政服務需要一個良好格式的地址結構一樣,面向服務的消息同樣也需要一個定 義良好的地址結構。這節裡,我們將會建立自己的地址結構(Scheme),看它可 以不可以廣泛適用於所有的消息應用系統,然後把它關聯到那個和WCF消息一起 使用的地址結構上。
在傳輸裡標記地址VS在消息裡標記地址
面向服務的消息直接在消息裡指定最終接受者。這是一個微不足道但是非常 重要的問題。如果消息目標在消息裡指定,一個完整的消息模式集合成為可能。 你將會在第3章《消息交換模式、拓撲和編排》裡學習到關於消息模式的更多知 識。
當我們直接把地址插入到消息時,我們在為更高效的消息處理做准備。效率 可以指代許多東西,在這個意義上,與創建消息的速度相反,我正在講的是實現 一個更先進的消息發送行為的容易性。和寫個信封地址需要花費時間一樣,序列 化地址到消息裡也需要耗費時間。無論如何,寫地址到信封上會改善郵政服務的 效率,序列化地址到消息裡改善處理效率,特別當更高級的消息發送行為要實現 (像消息路由和中介者)。
指定最終接受者
那什麼類型條目應該放到地址裡呢?對於發起者,地址應該可以標識消息的 最終接受者。因為最終接受者可能托管多個服務,所以我們應該有一個方式可以 唯一地區別最終接受者上的服務。一個地址元素也能夠描述托管服務的最終接受 者和服務本身。看一下下面的例子:
http://wintellect.com/OrderService
Internet時期,我們知道,地址由最終接受者的地址和我們可以使用的訪問 協議組成。因為大SO消息是SOAP消息,我們需要構造一些SOAP消息來傳達信息。
我們知道SOAP消息包含3種類型的元素:信封、包含多個消息塊的消息頭和消 息體。消息信封不是一個好的選擇,因為信封元素只能出現一次。選擇只有消息 頭和消息體可以作為候選了。所以消息體怎麼樣?從我們早期的討論,我們知道 消息體只是給最終的消息接受者使用的。經過排除過程以後,消息頭裡可以給我 們提供包含地址的邏輯空間。這樣消息頭塊看起來會是什麼樣子?這樣如何:
<Envelope>
<Header>
<To>http://wintellect.com/OrderService</To>
</Header>
<Body> …</Body>
</Envelope>
更高層次上,這個簡單的XML結構達到了我們標識最終接受者和我們要發送的 服務的目的。
指定初始發送者
在消息裡加入發送者信息也許有用,就像信件上的退信地址。增加發送者信 息有2個目的:為最終接受者指出發送者,為中介者指出發送者。我們已經看到 URL可以用來鑒別消息。所以事實上我們可以使用相同的結構來標識發送者。例 子如下:
<Envelope>
<Header>
<To>http://wintellect.com/ReceiveService</To>
<From>http://wintellect.com/SendService</From>
</Header>
<Body> …</Body>
</Envelope>
給SOAP增加簡單的元素來支持消息的來源,這個可以既可以被中介者也可以 被最終接受者使用。
指定錯誤發送地址
如有出了問題會如何處理消息?每個現代的計算平台都有一些方法去指示錯 誤和異常信息。這些消息處理機制使得我們的系統更加強壯、可預測和容易調試 。很自然就想到我們的消息應用系統也應該有這樣的機制。考慮到我們的消息已 經包含了<To> 和 <From>,我們可以發送所有的錯誤通知給 <From>元素定義的地址。為了錯誤處理,如果我們想讓錯誤通知發送到一 個特定的地址特別需要保存什麼呢?這個例子,我們必須創建另外一個元素:
<Envelope>
<Header>
<To>http://wintellect.com/OrderService</To>
<From>http://wintellect.com/SendService</From>
<Error>http://wintellect.com/ErrorService</Error>
</Header>
<Body> …</Body>
</Envelope>
增加<Error>元素到消息頭裡可以清楚地指出消息發送希望錯誤發送的 地址。因為URL在消息頭裡,它可以被消息接受者和中介者使用。
鑒別消息
我們簡單的地址結構需要發送者在消息裡增加我們的To、From和Error信息作 為消息頭塊,然後發送消息給最終接受者。當中介者或者最終接受者處理消息的 時候,可能會發生錯誤。這個錯誤與初始發送的消息完全不同。從初始發送者的 角度看,接受錯誤消息意味著自己的問題來了,但是特別是我們不知道的發送消 息導致的錯誤的時候。如果我們能把初始消息和錯誤消息關聯,對於調試、故障 分析和審計來說就太棒了。為了實現這個,在消息裡我們需要兩個元素:消息標 識元素和消息關聯元素。讓先我們看一下消息標識:
<Envelope>
<Header>
<MessageID></MessageID>
<To>http://wintellect.com/OrderService</To>
<From>http://wintellect.com/SendService</From>
<Error>http://wintellect.com/ErrorService</Error>
</Header>
<Body></Body>
</Envelope>
這個例子裡,我們把消息標識元素稱作<MessageID>。現在,我們可以 認為MessageID的值是一個全球唯一的數(例如GUID)。在產生上,這個數字對 於其他參與者沒有任何意義。如果初始發送者產生了一個如前面描述的消息,所 有的中介者和最終接受者都知道錯誤消息發送到哪裡,但是它們可以使用 MessageID去找到導致這個錯誤的特定消息。如果錯誤消息的接受者和初始發送 者不同,這些處理必須在它們之間交換信息區完全了解導致錯誤的消息。
關聯消息
如果我們假設一個中介者或者最終接受者處理消息的時候產生了錯誤,那麼 接下來就應該有一個新的消息被發送給錯誤元素指定的地址。如果一個中介者或 者最終接受者發送了一個完全的新的消息,中介者或者最終接受者就會成為新消 息的發送者。同樣地,錯誤消息頭塊裡的地址下載成為了新消息的最終接受者。 我們剛確定了導致錯誤的初始消息會包含一個MessageID元素。不知道為什麼, 錯誤消息需要包含一個引用MessageID的元素。初始消息和錯誤消息的關聯可以 通過RelatesTo元素描述:
<Envelope>
<Header>
<MessageID></MessageID>
<RelatesTo></RelatesTo>
<To>http://www.wintelelct.com/ErrorService</To>
<From>http://wintellect.com/OrderService</From>
<Error>http://wintellect.com/ErrorService</Error>
</Header>
<Body> …</Body>
</Envelope>
這個在http://wintellect.com/ErrorService的錯誤服務時最重的消息接受 者。當這個錯誤服務讀取消息,導致錯誤的消息的信息包含在RelatesTo元素裡 。雖然錯誤服務也許不對RelatesTo做任何事情,它可以被用作調試、故障分析 和審計。注意懂啊這個例子裡的To、 From和Error元素已經改變去反映消息的新 的上下文。
誰在監聽響應?
讓我們先不討論錯誤消息,回到初始消息。正如你看到的,我們有一個方式 去指定消息的最終接受者、初始發送者的地址、一個唯一標識和錯誤通知發送的 地址。同樣當處理初始消息的時候我們也想增加一個返回消息的地址也是可行的 。現實世界裡這種例子很多。比如,發貨單都有一個“回信到此”地址來區分初 始的發送地址。我們的SO消息需要一個類似的結構。我們能多使用一次地址的概 念與一個新的元素綁定來描述這個信息。在下面的例子裡我們稱這個新的元素為 ReplyTo:
<Envelope>
<Header>
<MessageID></MessageID>
<To>http://wintellect.com/OrderService</To>
<ReplyTo>http://wintellect.com/OrderReplyService</ReplyTo>
<From>http://wintellect.com/SendService</From>
<Error>http://wintellect.com/ErrorService</Error>
</Header>
<Body> …</Body>
</Envelope>
或許在相同的消息裡有From 和ReplyTo兩個元素,看起來有點重復。重要的 是記住,From 和ReplyTo兩個元素或許表示相同的服務,但是它們也可以描述不 同的服務。增加ReplyTo元素能夠簡單地為我們創建的消息頭塊增加更多的靈活 性和功能。
指定一個操作
下一個消息頭塊需要一些基礎,特別是你沒有太多處理Web服務的經驗。
Contoso Boomerang Corporation ATTN: New Customer Subscriptions 2611 Boomerang Way Atlanta, GA 30309
經驗來看,我們知道這個地址提到了Contoso Boomerang Corporation (Contoso回飛棒公司)。更准確點,我們知道這個地址在Contoso Boomerang Corporation組裡特別提到了New Customer Subscriptions
如果你希望發送郵件給一個大公司,你也許不需要特地指定一個部門。你可 以發送郵件給Contoso Boomerang Corporation並且希望一些人打開這個郵件, 猜一下誰會打開這個郵件,然後轉發給推斷的接受者。明顯這個過程和我們指定 准確的部門或者小組地址相比將花費更多的時間。
Contoso Boomerang Corporation可能包括幾個可以收到這個信件的組。每個 組或許有自己的一套處理流程。比如,Contoso或許有一個組負責簽訂新客戶, 另外一個組負責客戶支持,再有另外一個組服務新產品開發。在抽象層上,地址 可以為目標指定不懂級別的粒度,每個目標或許有自己的一套處理流程。
目前為止,我們已經創建了一個元素來定義最終接受者,一個reply-to接受 者,一個錯誤提醒的接受者,一個消息標識,一個關聯機制,初始發送者。我們 還沒有定義一個消息的操作。我們假設,現在我們可以使用另外一個URL來標識 一個動作(action)或者操作(operation)。下面的例子闡述了這個假設:
<Envelope>
<Header>
<MessageID></MessageID>
<To>http://wintellect.com/OrderService</To>
<Action>urn:ProcessOrder/Action>
<ReplyTo>http://wintellect.com/OrderReplyService</ReplyTo>
<From>http://wintellect.com/SendService</From>
<Error>http://wintellect.com/ErrorService</Error>
</Header>
<Body> …</Body>
</Envelope>
在這個例子裡,Action元素表示ProcessMsg操作應該在此消息上執行。 OrderService也可能定義了另外的操作。例如,通過下面的Action元素我們可以 發送另外一個消息去存檔消息操作:
<Envelope>
<Header>
<MessageID></MessageID>
<To>http://wintellect.com/OrderService</To>
<Action>urn:ArchiveMessage</Action>
<ReplyTo>http://someotherurl.com/OrderReplyService</ReplyTo&g t;
<From>http://wintellect.com/SendService</From>
<Error>http://wintellect.com/ErrorService</Error>
</Header>
<Body> </Body>
</Envelope>
標准消息頭塊的需求
我們已經粗略地定義了7個可以幫助我們標記地址的元素。我們可以假設我們 的元素名稱可以被普遍接受。我們能建立理解這些元素的基礎架構並且在我們每 個消息參與者裡使用這個基礎架構。換句換說,我們不能發送這些消息到一個不 知道我們7個元素意義的應用系統裡。同樣地,我們的應用系統不能夠接受包含 不同地址頭的消息。例如,另外一個廠商或許已經定義了下面這樣的消息 頭;
<Envelope>
<Header>
<MessageIdentifier>1</MessageIdentifier>
<SendTo>http://wintellect.com/OrderService</SendTo>
<Op>http://wintellect.com/OrderService/ArchiveMessage</Op>
<Reply>http://someotherurl.com/OrderReplyService</Reply> <SentFrom>http://wintellect.com/SendService</SentFrom>
<OnError>http://wintellect.com/ErrorService</OnError>
</Header>
<Body></Body>
</Envelope>
包含我們的基礎架構的應用系統不能夠處理這個消息。
如果我們打算調查一下大部分企業應用,我們會看到軟件廠商已經遵守這個 模型定義了他們自己消息。過了幾年,SOAP已經成為大家認可的消息格式,但是 還沒有就消息頭塊出現在消息裡達成共識,結果,應用系統部能輕易地互操作。 真SOAP消息的互操作性需要一個可以通行於各個廠商的消息頭塊。如第一章裡提 到的,WS-*規范通過定義一個公共的消息頭經過漫長的努力解決這個問題。
【地址】:http://www.cnblogs.com/frank_xl/