精彩的人生

          好好工作,好好生活

          BlogJava 首頁 新隨筆 聯(lián)系 聚合 管理
            147 Posts :: 0 Stories :: 250 Comments :: 0 Trackbacks

          深入學(xué)習(xí)Web Service系列之 異步開發(fā)模式

          ——《深入學(xué)習(xí) Web Service 系列》之一

          Terrylee 2005 12 4

          概述

          在本篇隨筆中,通過一些簡單的示例來說一下 Web Service 中的異步調(diào)用模式。調(diào)用 Web Service 方法有兩種方式,同步調(diào)用和異步調(diào)用。同步調(diào)用是程序繼續(xù)執(zhí)行前等候調(diào)用的完成,而異步調(diào)用在后臺繼續(xù)時,程序也繼續(xù)執(zhí)行,不必等待方法處理完成而直接返回。具體的調(diào)用流程見下圖:

          ?

          對于同步調(diào)用方法而言, UI 線程依賴于方法的實現(xiàn),方法執(zhí)行時間過長將導(dǎo)致 UI 無法及時與用戶進行交互。我們知道,在 Windows 客戶端中,每個進程都有單一的 UI 進程,在服務(wù)器中,可擴展性依賴于線程的使用。對于異步調(diào)用方法而言,能夠及時于用戶交互響應(yīng),從而提供了良好的用戶體驗;同時也可以改善服務(wù)器的可擴展性,將服務(wù)器與通訊問題隔離。

          客戶端異步調(diào)用方法

          在客戶端異步調(diào)用是完全基于 Proxy 的方法,異步行為最簡單的模式。 Visual Studio WSDL.EXE 提供對它的直接支持。所以我們不必在 Web 服務(wù)應(yīng)用程序中編寫額外的代碼來處理異步調(diào)用。

          遍及 .NET Framework 的異步調(diào)用有一個基礎(chǔ)的設(shè)計模式: Begin 方法和 End 方法,他們分別用于開始和終止異步處理。 Visual Studio WSDL.exe 生成了這兩種方法:

          Begin<WebServiceMethodName> ——該方法通知 Web 服務(wù)開始處理調(diào)用,并立即返回。該方法不返回 Web 服務(wù)調(diào)用所指定的數(shù)據(jù)類型,而是返回一種實現(xiàn) IasyncResult 接口的數(shù)據(jù)類型。

          End<WebServiceMethodName> ——該方法通知 Web 服務(wù)返回先前啟動的 Web 方法所生成的結(jié)果。

          IasyncResult 接口包含了 WaitHandle 類型的 AsyncWaitHandle 特性。這個公共接口允許用戶的客戶應(yīng)用程序等待調(diào)用,而且,該接口將用 Any All 語義(例如 WaitHandle.WaitOne WaitAny WaitAll )作為信號通知客戶應(yīng)用程序。例如,如果想要客戶應(yīng)用程序異步等候一個 Web 方法,可調(diào)用 WaitOne 來處理要完成的 Web 服務(wù)。

          一般來說,客戶端異步代理方法有兩種實現(xiàn)機制:使用同步對象和回調(diào)機制(也許你可能對用這個詞不習(xí)慣,實在找不到第二個詞來代替,暫且這樣稱呼吧)

          同步對象

          同步對象允許用戶對 Web 服務(wù)的方法進行調(diào)用(使用 Begin 方法),然后繼續(xù)處理。在后面的程序中,可以調(diào)用 End 方法,傳遞同步對象,以便得到調(diào)用結(jié)果。這種方式下,能夠繼續(xù)執(zhí)行函數(shù)中的程序流程,而不執(zhí)行回調(diào)處理。在這里 調(diào)用 WaitOne() 方法會掛起當前線程,避免忙等待的發(fā)生,直到 Web Services 方法調(diào)用結(jié)束返回后,該線程才會被重新喚起。

          示例代碼:

          ?1 /// ? <summary>
          ?2 /// ?利用同步對象實現(xiàn)異步調(diào)用
          ?3 /// ? </summary>
          ?4 /// ? <param?name="sender"></param>
          ?5 /// ? <param?name="e"></param>

          ?6 private ? void ?btn_AsyncClient_Click( object ?sender,?System.EventArgs?e)
          ?7 {
          ?8 ????IAsyncResult?ar? = ?wsc.BeginHello( this .txt_UserName.Text,? null ,? null );
          ?9
          10
          11 ????MessageBox.Show( " Continue?to?do?some?other?things " );
          12
          13 ????ar.AsyncWaitHandle.WaitOne();
          14
          15 ????strHello? = ?wsc.EndHello(ar);
          16
          17 ???? this .rtb_Result.Text? = ?strHello;
          18 }

          回調(diào)機制

          從本質(zhì)上說,異步回調(diào)機制是委托的 .NET 等價物,它通過在異步操作完成時建立一個被調(diào)用的單獨方法來進行工作。調(diào)用應(yīng)用程序能夠繼續(xù)處理其他的任務(wù),直到回調(diào)函數(shù)被調(diào)用為止。這就意味著處理已經(jīng)完成了,應(yīng)用程序可以正常運行了。使用同步對象不同于回調(diào)機制的區(qū)別是,當檢查 Web 方法是否已經(jīng)完成,以及檢查 Web 方法中是否含有需要的結(jié)果時,我們無法對其進行控制,而在回調(diào)的情況中, Web 方法一旦完成,這些工作就會被自動執(zhí)行。

          示例代碼:

          ?1 /// ? <summary>
          ?2 /// ?顯示結(jié)果
          ?3 /// ? </summary>
          ?4 /// ? <param?name="sender"></param>
          ?5 /// ? <param?name="e"></param>

          ?6 public ? void ?UpdateResult( object ?sender,?EventArgs?e)
          ?7 {
          ?8 ???? this .rtb_Result.Text? = ?strHello;
          ?9 }

          10
          11 public ? void ?OnHelloComplete(IAsyncResult?ar)
          12 {
          13 ????strHello? = ?wsc.EndHello(ar);
          14
          15 ???? this .rtb_Result.Invoke( new ?EventHandler(UpdateResult));
          16 }

          17
          18 /// ? <summary>
          19 /// ?用回調(diào)機制實現(xiàn)異步調(diào)用
          20 /// ? </summary>
          21 /// ? <param?name="sender"></param>
          22 /// ? <param?name="e"></param>

          23 private ? void ?btn_CallBack_Click( object ?sender,?System.EventArgs?e)
          24 {
          25 ????AsyncCallback?cb? = ? new ?AsyncCallback(OnHelloComplete);
          26
          27 ????wsc.BeginHello( this .txt_UserName.Text,?cb,? null );
          28 }

          使用回調(diào)機制還是同步對象取決于用戶所面臨的具體情況。在檢查異步調(diào)用是否完成時,如果愿意對處理過程進行控制,那么可以選擇使用同步對象。如果覺得自己編寫代碼來完成對 Web 服務(wù)的調(diào)用,且當方法一旦執(zhí)行完畢就立即由所調(diào)用的特殊函數(shù)來處理所返回的結(jié)果更適合一些,那么就更適合用回調(diào)機制。

          在客戶端使用異步方法調(diào)用,可以改進 UI 響應(yīng)度,在服務(wù)器端不需要實現(xiàn)異步操作,對服務(wù)器來說是透明的,而且客戶端能夠在任何時間選擇阻塞。

          服務(wù)端使用 Soap One-Way 方法

          在服務(wù)器端使用 One-Way 方法實現(xiàn)異步調(diào)用,其實質(zhì)是將單項消息發(fā)送到端點。這種方式的特點是方法沒有返回值,客戶端方法不會從調(diào)用的服務(wù)器端方法中收到返回值;我們無法判斷方法結(jié)束的時間,對于結(jié)果需要顯式通知或者輪詢。

          Web 服務(wù)端,我們使用 [SoapDocumentMethod] 定義 One-Way 方法:

          ?[System.Web.Services.Protocols.SoapDocumentMethod(OneWay = true )]

          示例代碼:

          ?1 /// ? <summary>
          ?2 /// ?One-Way方式的異步調(diào)用Set
          ?3 /// ? </summary>
          ?4 /// ? <param?name="sender"></param>
          ?5 /// ? <param?name="e"></param>

          ?6 private ? void ?btn_OneWay_Click( object ?sender,?System.EventArgs?e)
          ?7 {
          ?8 ????wsc.SetHello( this .txt_UserName.Text);????
          ?9 }

          10
          11 /// ? <summary>
          12 /// ?One-Way方式的異步調(diào)用Get
          13 /// ? </summary>
          14 /// ? <param?name="sender"></param>
          15 /// ? <param?name="e"></param>

          16 private ? void ?btn_onewayGet_Click( object ?sender,?System.EventArgs?e)
          17 {
          18 ????strHello? = ?wsc.GetHello();
          19
          20 ???? this .rtb_Result.Text? = ?strHello;
          21 }

          One-Way 方法不適合于下列情況:

          l???????? 方法需要對結(jié)果輪詢

          l???????? 方法需要同步

          服務(wù)端使用 WSE SoapSender SoapRecevier

          在進行本部分內(nèi)容之前,我們需要安裝 WSE2.0 WSE 支持面向消息的編程,為我們提供了 SoapSender SoapReceiver 基類,它能夠支持發(fā)送和接收 SoapEnvelopes ,同時它也通過 SoapClient SoapService 提供了更多的事務(wù)支持。 SoapSender SoapReceiver 在客戶端和服務(wù)端同時實現(xiàn),客戶端使用 SoapSender 發(fā)送消息,同時可選擇使用 SoapReceiver 接收消息;服務(wù)端使用 SoapReceiver 接收消息,同時也可以選擇使用 SoapSender 發(fā)送通知和回應(yīng)。

          示例代碼:

          ?客戶端:

          ?1 /// ? <summary>
          ?2 ???? /// ?自定義的消息接收類
          ?3 ???? /// ? </summary>

          ?4 ???? public ? class ?MyReceiver:?SoapReceiver
          ?5 ???? {
          ?6 ???????? public ? static ?Form1?form;
          ?7 ???????? private ? string ?strBody;
          ?8
          ?9 ???????? protected ? override ? void ?Receive(SoapEnvelope?envelope)
          10 ???????? {
          11 ????????????strBody? = ?envelope.InnerText;
          12
          13 ???????????? /// 注意:在進行此項之前,一定要把rtb_Result控件的屬性設(shè)為Public
          14 ????????????form.rtb_Result.Invoke( new ?EventHandler(UpdateBody));
          15 ????????}

          16
          17 ???????? void ?UpdateBody( object ?sender,?System.EventArgs?e)
          18 ???????? {
          19 ????????????form.rtb_Result.Text? = ?strBody;
          20 ????????}

          21 ????}

          1 /// ? <summary>
          2 /// ?用WSE實現(xiàn)異步調(diào)用
          3 /// ? </summary>
          4 /// ? <param?name="sender"></param>
          5 /// ? <param?name="e"></param>

          6 private ? void ?button4_Click( object ?sender,?System.EventArgs?e)
          7 {
          8 ????wsc.FireEvent();
          9 }

          Web Service端:

          ?1 private ?ArrayList?Listeners
          ?2 ???????? {
          ?3 ???????????? get
          ?4 ???????????? {
          ?5 ???????????????? return ?(ArrayList)Application[ " Listeners " ];
          ?6 ????????????}

          ?7 ????????}

          ?8
          ?9 ????????[WebMethod]
          10 ???????? public ? void ?AddListener( string ?listener)
          11 ???????? {
          12 ????????????ArrayList?alist? = ?(ArrayList)Application[ " Listeners " ];
          13
          14 ???????????? if (alist? == ? null )
          15 ????????????????alist? = ? new ?ArrayList();
          16
          17 ????????????alist.Add(listener);
          18
          19 ????????????Application[ " Listeners " ]? = ?alist;
          20
          21 ????????}

          22
          23 ????????[WebMethod]
          24 ???????? public ? void ?FireEvent()
          25 ???????? {
          26 ???????????? int ?i;
          27
          28 ???????????? for (i? = ? 0 ;i? < ? this .Listeners.Count;i ++ )
          29 ???????????? {
          30 ????????????????SoapEnvelope?envelope? = ? new ?SoapEnvelope();
          31
          32 ????????????????envelope.SetBodyObject( " Hello?World! " );
          33
          34 ????????????????envelope.Context.Addressing.Action? = ? new ?Action(( string )( this .Listeners[i]));
          35
          36 ????????????????envelope.Context.Addressing.ReplyTo? = ? new ?ReplyTo( new ?System.Uri(( string )( this .Listeners[i])));
          37
          38 ????????????????SoapSender?peerProxy? = ? new ?SoapSender( new ?System.Uri(( string )( this .Listeners[i])));
          39
          40 ????????????????peerProxy.Send(envelope);
          41 ????????????}

          42 ????????}

          服務(wù)端使用 WSE 自定義 SoapMSMQ 傳輸

          SoapMSMQ 是一款開源軟件,簡化使用 WSE 進行 MSMQ 操作,下載地址:

          http://www.codeproject.com/useritems/SoapMSMQ.asp

          SoapMSMQ 完全支持事務(wù),具有如下特點:

          l???????? 在事務(wù)中,請求要被同步初始化

          l???????? 同步階段排隊請求,并且返回令牌

          l???????? 異步階段處理各個事務(wù)

          l???????? 所有持有令牌的請求都保證會被處理,但可能會不成功

          l???????? 支持向客戶端發(fā)送通知

          SoapMSMQ 感興趣的朋友可以下載下來后,做進一步的研究。

          總結(jié)

          異步方法調(diào)用改善了客戶端的響應(yīng)和用戶體驗,增加了服務(wù)端的可擴展性。當方法需要耗費大量的時間時,可以采用異步方式調(diào)用,提供系統(tǒng)并發(fā)處理的能力。對于異步方式的開發(fā),我們可以有如上所述的廣泛選擇。

          示例程序界面:

          下載地址:

          http://www.cnblogs.com/Files/Terrylee/AsyncDemo.rar

          原文地址:http://terrylee.cnblogs.com/archive/2005/12/05/290845.html

          posted on 2006-05-07 15:28 hopeshared 閱讀(781) 評論(0)  編輯  收藏 所屬分類: Web Service
          主站蜘蛛池模板: 凌云县| 宝应县| 正蓝旗| 赞皇县| 清河县| 蓝山县| 孟村| 穆棱市| 罗江县| 昂仁县| 温泉县| 宣威市| 华容县| 九寨沟县| 伊川县| 泰宁县| 漠河县| 方山县| 同仁县| 宜阳县| 包头市| 儋州市| 烟台市| 会宁县| 岳池县| 涿鹿县| 崇信县| 新沂市| 和田县| 松江区| 田阳县| 肥乡县| 灵宝市| 高雄市| 万安县| 望谟县| 岑巩县| 新源县| 西和县| 沙田区| 肇东市|