精彩的人生

好好工作,好好生活

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 阅读(766) 评论(0)  编辑  收藏 所属分类: Web Service

只有注册用户登录后才能发表评论。


网站导航: