精彩的人生

          好好工作,好好生活

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

          深入學習Web Service系列之 異步開發模式

          ——《深入學習 Web Service 系列》之一

          Terrylee 2005 12 4

          概述

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

          ?

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

          客戶端異步調用方法

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

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

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

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

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

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

          同步對象

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

          示例代碼:

          ?1 /// ? <summary>
          ?2 /// ?利用同步對象實現異步調用
          ?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 }

          回調機制

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

          示例代碼:

          ?1 /// ? <summary>
          ?2 /// ?顯示結果
          ?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 /// ?用回調機制實現異步調用
          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 }

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

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

          服務端使用 Soap One-Way 方法

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

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

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

          示例代碼:

          ?1 /// ? <summary>
          ?2 /// ?One-Way方式的異步調用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方式的異步調用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???????? 方法需要對結果輪詢

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

          服務端使用 WSE SoapSender SoapRecevier

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

          示例代碼:

          ?客戶端:

          ?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控件的屬性設為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實現異步調用
          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 ????????}

          服務端使用 WSE 自定義 SoapMSMQ 傳輸

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

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

          SoapMSMQ 完全支持事務,具有如下特點:

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

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

          l???????? 異步階段處理各個事務

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

          l???????? 支持向客戶端發送通知

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

          總結

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

          示例程序界面:

          下載地址:

          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
          主站蜘蛛池模板: 柘荣县| 甘泉县| 巩义市| 昌江| 洪湖市| 同心县| 轮台县| 吴江市| 会昌县| 萍乡市| 苏尼特左旗| 余江县| 灵宝市| 库伦旗| 陆良县| 庆云县| 新疆| 正蓝旗| 平安县| 长宁区| 阿拉善盟| 城口县| 武强县| 南昌县| 开阳县| 成安县| 威海市| 镇远县| 赫章县| 长寿区| 铜川市| 陇南市| 那曲县| 五家渠市| 房山区| 关岭| 泸西县| 灵台县| 盐津县| 兴山县| 永春县|