編寫者:鄭昀@ultrapower
編寫日期:2005-04-13
修改日期:2005-05
<b>目的:</b><b></b>
我們建立這種互動關系的目的是,在web service和windows service(或者其他windows應用)之間建立起一種穩固的可擴充的不受地域限制的互動關系。
這種互動關系的優點是:
<b>完全異步:</b><b></b>
web service和windows service/windows form都可以實作互動的異步性,也就說,二者的互動完全是通過delegate和wse2.0消息機制實作的,彼此依賴性降低,web service可以像一個二傳手,不斷地将使用者發起的請求路由到背景服務,web service不用和windows service之間保持長連接配接;windows service處理請求完畢,就發送soap消息給web service的http endpoint。
你甚至可以在使用wse2.0的msmq transport來替代http/tcp channel作為底層通信。
<b>可擴充:</b><b></b>
這種soap消息很容易定制和擴充新的標頭定義。
<b>可分布:</b><b></b>
由于webservice的http endpoint位址可以随着web service發消息給背景服務,是以webservice部署在哪裡無關緊要,都可以和windows service保持互動。webservice是通過wse2.0中的<b>ws_addressing</b>機制把消息路由給windows service的,是以二者可以部署到不同的機器上,隻需要改變webservice的配置檔案即可,背景服務能夠根據傳過來的soap包中的replyto字段獲知應該如何給哪裡的http終結點回傳消息。
由于web service的執行身份受限,是以我們無法直接讓web service申請作為一個soapreceiver,而是通過下面的web.config定義來制定本虛拟目錄的.ashx終結點,進而通過<b>ws_addressing</b>和<b>ws_messaging</b>機制來完成<b>web service</b>與<b>windows service</b>之間的訂閱/釋出機制。
在 asp.net 中,可以通過ihttphandler,将 soapreceiver 與 http 信道進行內建。如果檢視一下soapreceiver 的定義,您會注意到它實作了 ihttphandler:
public abstract class soapreceiver : soapport, ihttphandler
{
。。。
}
<b>由于這一點,任何</b><b> soapreceiver </b><b>或</b><b> sendservice </b><b>類現在都能夠在</b><b> asp.net </b><b>中配置為</b><b> http </b><b>處理程式。</b>通過在 web.config 檔案的 httphandlers 部分添加一個新的映射,使用者能夠配置 http 處理程式。web.config 項将把 verb/path 組合映射到 soapreceiver 類型:
首先,我們通過在web service的配置檔案web.config中,加入如下示範片斷:
<configuration>
<configsections>
<section name="microsoft.web.services"
type="microsoft.web.services.configuration.webservicesconfiguration,
microsoft.web.services, version=2.0.0.0, culture=neutral,
publickeytoken=31bf3856ad364e35" />
</configsections>
<system.web>
<httphandlers>
<!-- 為了讓我們的webservice能夠接收到來自于背景偵聽服務的soap消息
我們讓webservice繼承自soapreceiver,并實作了void receive(soapenvelope envelope),
這樣exe通過向
new uri("http://"+ system.net.dns.gethostname() + "/myservice/getreceiver.ashx")
發送soap消息,那麼soapreceiver的receive回調函數将被調用
-->
<add type="mywebservice.myinterface" path="getreceiver.ashx" verb="*" />
</httphandlers>
把這組代碼放到适當的位置,将針對每條輸入此虛拟目錄并指向 getreceiver.ashx 的消息而調用 myservice。現在我們不必擔心通過調用 soapreceiver.add 來配置 soapreceiver/soapservice,因為 asp.net 本質上代替您完成了此任務。
如果windows service通過soapsender,就可以把消息發送到我們定義的 http 終結點(http://localhost/myservice/getreceiver.ashx),它與使用 tcp 信道接收soap消息的工作方式相同,隻是現在它通過 http 進行通訊。
我們在webservice中加上幾個靜态的哈希表,存儲了用戶端的回調函數以及其他資訊,還有對應的查詢請求等,相當于儲存了會話狀态,進而能夠在這些哈希表的幫助下完成與windows服務之間的異步互動,以及與用戶端調用者之間的異步互動。
實作異步 xml web services 方法應遵循 .net framework 異步設計模式。
<b>第一步,将我們的異步</b><b> xml web services </b><b>方法</b><b>getreceive</b><b>拆分成兩個方法。</b><b></b>
每個方法都有相同的基名稱,即一個以 begin 開始,另一個以 end 開始;
<b>第二步,實作異步</b><b>web service</b><b>的</b><b>begingetreceive</b><b>方法:</b><b></b>
begingetreceive 方法的參數清單包含方法功能的所有 in 和 by reference 參數,以及追加到結尾的兩個參數。
by reference 參數作為 in 參數列出。
倒數第二個參數必須為 asynccallback。asynccallback 參數允許用戶端提供委托,在方法完成時将調用該委托。
當一個異步 xml web services 方法調用另一個異步方法時,此參數可被傳遞到該方法的倒數第二個參數。
最後一個參數是 object。object 參數允許調用方為方法提供狀态資訊。當一個異步 xml web services 方法調用另一個異步方法時,此參數将被傳遞到該方法的最後一個參數。
傳回值必須為 iasyncresult 類型。
<b>第三步,實作異步</b><b>web service</b><b>的</b><b>endgetreceive</b><b>方法:</b><b></b>
endgetreceive 方法的參數清單包含 iasyncresult 參數,此參數後面帶有特定于該方法功能的任意 out 和 by reference 參數。
傳回值類型與異步 xml web services 方法的傳回值類型相同。
by reference 參數作為 out 參數列出。
我們與一般的異步web service不同之處在于,begingetreceive 方法中又調用的
iasyncresult arr = prcdelegate.begininvoke(null, callback, asyncstate);
方法是類内部定義的“processreceive”函數,它實際上還是一個異步處理消息過程,它隻是把要處理的查詢請求用soapsender發送給背景服務,之後就傳回,不再等待。
<b>第四步,等到背景服務把結果發送給本</b><b>web service</b><b>的</b><b>http</b><b>終結點,我們再把結果都存儲在哈希表中,然後回調調用者。</b><b></b>
<b>第五步,調用者收到回調後,就調用我們</b><b>web service</b><b>的</b><b>endgetreceive</b><b>方法,進而從哈希表中拿到結果集。</b><b></b>
<b> </b>
上面描述的流程如下一節的圖檔所示。
由于web service運作的身份是asp.net使用者,而soapreceiver.add方法對執行權限要求較高,是以我們采用http終結點的方式,再加上幾個靜态的哈希表,進而完成了與背景偵聽服務之間的異步互動,以及與用戶端調用者之間的異步互動。
圖1 互動流程步驟說明
下面我們具體講解一下:
首先,調用者請求web serviced的begingetreceive方法,這個方法再異步調用processreceive方法它負責組裝出一個<b>soapenvelope</b>,并向uri為
soap.tcp://hostname:port/yourreceivername
的目标endpoint,用soapsender.send發送這個<b>soapenvelope</b>。一方面用于通知訂閱關系,另一方面傳遞了各項參數,以及預先生成的guid。之後就将處理權傳回調用者。
這裡包含了圖中的1,2,3三步:
其次,正在監聽的偵聽服務收到了消息,進行處理:
添加這個訂閱者的各種資訊到靜态哈希表;
利用i/o完成端口異步執行各種任務;
把結果集或者錯誤資訊通過web service http終結點通知訂閱者。
這裡包含了圖中的4,5,6三步:
最後,訂閱者web service收到通知後,通知用戶端調用者的回調函數來取回結果集,進而将結果集或者錯誤原因傳回給用戶端。
編寫者:鄭昀@ultrapower