深入学习Web Service系列----异步开发模式

概述

在本篇随笔中,通过一些简单的示例来说一下Web Service中的异步调用模式。调用Web Service方法有两种方式,同步调用和异步调用。同步调用是程序继续执行前等候调用的完成,而异步调用在后台继续时,程序也继续执行,不必等待方法处理完成而直接返回。具体的调用流程见下图:

 

对于同步调用方法而言,UI线程依赖于方法的实现,方法执行时间过长将导致UI无法及时与用户进行交互。我们知道,在Windows客户端中,每个进程都有单一的UI进程,在服务器中,可扩展性依赖于线程的使用。对于异步调用方法而言,能够及时于用户交互响应,从而提供了良好的用户体验;同时也可以改善服务器的可扩展性,将服务器与通讯问题隔离。

 

客户端异步调用方法

在客户端异步调用是完全基于Proxy的方法,异步行为最简单的模式。Visual StudioWSDL.EXE提供对它的直接支持。所以我们不必在Web服务应用程序中编写额外的代码来处理异步调用。

遍及.NET Framework的异步调用有一个基础的设计模式:Begin方法和End方法,他们分别用于开始和终止异步处理。Visual StudioWSDL.exe生成了这两种方法:

Begin<WebServiceMethodName>——该方法通知Web服务开始处理调用,并立即返回。该方法不返回Web服务调用所指定的数据类型,而是返回一种实现IasyncResult接口的数据类型。

End<WebServiceMethodName>——该方法通知Web服务返回先前启动的Web方法所生成的结果。

IasyncResult接口包含了WaitHandle类型的AsyncWaitHandle特性。这个公共接口允许用户的客户应用程序等待调用,而且,该接口将用AnyAll语义(例如WaitHandle.WaitOneWaitAnyWaitAll)作为信号通知客户应用程序。例如,如果想要客户应用程序异步等候一个Web方法,可调用WaitOne来处理要完成的Web服务。

一般来说,客户端异步代理方法有两种实现机制:使用同步对象和回调机制(也许你可能对用这个词不习惯,实在找不到第二个词来代替,暂且这样称呼吧)

同步对象

同步对象允许用户对Web服务的方法进行调用(使用Begin方法),然后继续处理。在后面的程序中,可以调用End方法,传递同步对象,以便得到调用结果。这种方式下,能够继续执行函数中的程序流程,而不执行回调处理。在这里调用WaitOne()方法会挂起当前线程,避免忙等待的发生,直到Web Services方法调用结束返回后,该线程才会被重新唤起。

示例代码:

/// <summary>
/// 利用同步对象实现异步调用
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_AsyncClient_Click(object sender, System.EventArgs e)
{IAsyncResult ar = wsc.BeginHello(this.txt_UserName.Text, null, null);MessageBox.Show("Continue to do some other things");ar.AsyncWaitHandle.WaitOne();strHello = wsc.EndHello(ar);this.rtb_Result.Text = strHello;
}

 

 

 

回调机制

从本质上说,异步回调机制是委托的.NET等价物,它通过在异步操作完成时建立一个被调用的单独方法来进行工作。调用应用程序能够继续处理其他的任务,直到回调函数被调用为止。这就意味着处理已经完成了,应用程序可以正常运行了。使用同步对象不同于回调机制的区别是,当检查Web方法是否已经完成,以及检查Web方法中是否含有需要的结果时,我们无法对其进行控制,而在回调的情况中,Web方法一旦完成,这些工作就会被自动执行。

示例代码:

/// <summary>
/// 显示结果
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public void UpdateResult(object sender, EventArgs e)
{this.rtb_Result.Text = strHello;
}public void OnHelloComplete(IAsyncResult ar)
{strHello = wsc.EndHello(ar);this.rtb_Result.Invoke(new EventHandler(UpdateResult));
}/// <summary>
/// 用回调机制实现异步调用
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_CallBack_Click(object sender, System.EventArgs e)
{AsyncCallback cb = new AsyncCallback(OnHelloComplete);wsc.BeginHello(this.txt_UserName.Text, cb, null);
}

 

 

 

使用回调机制还是同步对象取决于用户所面临的具体情况。在检查异步调用是否完成时,如果愿意对处理过程进行控制,那么可以选择使用同步对象。如果觉得自己编写代码来完成对Web服务的调用,且当方法一旦执行完毕就立即由所调用的特殊函数来处理所返回的结果更适合一些,那么就更适合用回调机制。

在客户端使用异步方法调用,可以改进UI响应度,在服务器端不需要实现异步操作,对服务器来说是透明的,而且客户端能够在任何时间选择阻塞。

 

服务端使用Soap One-Way方法

在服务器端使用One-Way方法实现异步调用,其实质是将单项消息发送到端点。这种方式的特点是方法没有返回值,客户端方法不会从调用的服务器端方法中收到返回值;我们无法判断方法结束的时间,对于结果需要显式通知或者轮询。

 

Web 服务端,我们使用[SoapDocumentMethod]定义One-Way方法:

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

示例代码:

/// <summary>
/// One-Way方式的异步调用Set
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_OneWay_Click(object sender, System.EventArgs e)
{wsc.SetHello(this.txt_UserName.Text);    
}/// <summary>
/// One-Way方式的异步调用Get
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btn_onewayGet_Click(object sender, System.EventArgs e)
{strHello = wsc.GetHello();this.rtb_Result.Text = strHello;
}

 

 

 

One-Way方法不适合于下列情况:

l         方法需要对结果轮询

l         方法需要同步

 

服务端使用WSE SoapSenderSoapRecevier

在进行本部分内容之前,我们需要安装WSE2.0WSE支持面向消息的编程,为我们提供了SoapSenderSoapReceiver基类,它能够支持发送和接收SoapEnvelopes,同时它也通过SoapClientSoapService提供了更多的事务支持。SoapSenderSoapReceiver在客户端和服务端同时实现,客户端使用SoapSender发送消息,同时可选择使用SoapReceiver接收消息;服务端使用SoapReceiver接收消息,同时也可以选择使用SoapSender发送通知和回应。

示例代码:

 客户端:

    /// <summary>/// 自定义的消息接收类/// </summary>public class MyReceiver: SoapReceiver{public static Form1 form;private string strBody;protected override void Receive(SoapEnvelope envelope){strBody = envelope.InnerText;///注意:在进行此项之前,一定要把rtb_Result控件的属性设为Publicform.rtb_Result.Invoke(new EventHandler(UpdateBody));}void UpdateBody(object sender, System.EventArgs e){form.rtb_Result.Text = strBody;}}
/**************************************************/
/// <summary>
/// 用WSE实现异步调用
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button4_Click(object sender, System.EventArgs e)
{wsc.FireEvent();
}

 

Web Service端:

        private ArrayList Listeners{get{return (ArrayList)Application["Listeners"];}}[WebMethod]public void AddListener(string listener){ArrayList alist = (ArrayList)Application["Listeners"];if(alist == null)alist = new ArrayList();alist.Add(listener);Application["Listeners"] = alist;}[WebMethod]public void FireEvent(){int i;for(i = 0;i < this.Listeners.Count;i++){SoapEnvelope envelope = new SoapEnvelope();envelope.SetBodyObject("Hello World!");envelope.Context.Addressing.Action = new Action((string)(this.Listeners[i]));envelope.Context.Addressing.ReplyTo = new ReplyTo(new System.Uri((string)(this.Listeners[i])));SoapSender peerProxy = new SoapSender(new System.Uri((string)(this.Listeners[i])));peerProxy.Send(envelope);}}

 

服务端使用WSE 自定义SoapMSMQ传输

SoapMSMQ是一款开源软件,简化使用WSE进行MSMQ操作,下载地址:

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

SoapMSMQ完全支持事务,具有如下特点:

l         在事务中,请求要被同步初始化

l         同步阶段排队请求,并且返回令牌

l         异步阶段处理各个事务

l         所有持有令牌的请求都保证会被处理,但可能会不成功

l         支持向客户端发送通知

SoapMSMQ感兴趣的朋友可以下载下来后,做进一步的研究。

 

总结

异步方法调用改善了客户端的响应和用户体验,增加了服务端的可扩展性。当方法需要耗费大量的时间时,可以采用异步方式调用,提供系统并发处理的能力。对于异步方式的开发,我们可以有如上所述的广泛选择。

 

示例程序界面:

下载地址:http://files.cnblogs.com/Terrylee/AsyncDemo.rar

出处:http://www.cnblogs.com/Terrylee/archive/2005/12/05/290845.html

转载于:https://www.cnblogs.com/mq0036/p/4029497.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/359525.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java 实现excel样式设置(居中、字体、大小、换行、合并行,列宽、指定特定字符串样式等)

HSSFWorkbook workbook new HSSFWorkbook(); Sheet sheet workbook.createSheet(); sheet.setColumnWidth(0, 30*256);//设置当前sheet页第一列宽度 sheet.setColumnWidth(1, 70*256);//第二列宽度 CellStyle style workbook.createCellStyle(); Font font workbook.cre…

可选依赖项

有时您正在编写的库可能具有可选的依赖项。 例如“如果apache http客户端在类路径上&#xff0c;请使用它&#xff1b;否则&#xff0c;请使用它。 否则–退回到HttpURLConnection”。 为什么要这么做&#xff1f; 由于各种原因–在分发库时&#xff0c;您可能不想强加较大的依…

XML-RPC协议学习

XML-RPC调用包括2部分&#xff1a;客户端client&#xff08;调用线程&#xff09;、服务器端server&#xff08;被调用的线程&#xff09;。服务端是通过特定的URL获得的&#xff0c;调用过程如下&#xff1a; 1.客户端程序使用XML-RPC客户端发出作业请求&#xff0c;指定方法名…

extjs tree 遍历树节点并设置选中

function initTreeChecked(){//获取根节点 var rootnoe Ext.getCmp("id").getRootNode();; setAllNodes(rootnoe); } //遍历所有节点 function setAllNodes(node){ setNodeChecked(node);//设置选中 var nodesnode.childNodes; for(var i0;i<…

Android开发中调用系统窗口的方法

//直接拨号 Intent callIntent new Intent(Intent.ACTION_CALL,Uri.parse("tel:12345678")); startActivity(callIntent); //将电话号码传入拨号程序 Intent dialIntent new Intent(Intent.ACTION_DIAL,Uri.parse("tel:12345678")); startActivity(dial…

navicate导出导入表数据问题

1.导出导入json&#xff0c;如下图&#xff0c;右击表点击导出向导&#xff0c;选择json导出类型&#xff0c;根据提示导出即可。 导入时&#xff0c;右击接收的表&#xff0c;点击导入向导&#xff0c;根据提示即可快速导入&#xff08;注&#xff1a;不同系统之间导出导入易…

spring pojo_使用Spring将POJO公开为JMX MBean

spring pojo这是一个非常不错的教程&#xff0c;介绍了如何通过我们最新的JCG合作伙伴 “ The Holy Java ”博客&#xff08;很酷的名字&#xff09;实现“ 用Spring轻松将POJO作为JMX MBean公开 ”。 &#xff08;注意&#xff1a;对原始帖子进行了少量编辑以提高可读性&#…

android地图实时标记

问题描述我在用百度地图给上边做标注的时候&#xff0c;用了一下主要代码&#xff1a;class MyOverlayItem extends ItemizedOverlay<OverlayItem>{ private ArrayList<OverlayItem> mOverlayList new ArrayList<OverlayItem>();private double mLat1 34.0…

tongweb通过控制台简单设置确认相关常用参数

1.环境版本 jdk&#xff0c;tongweb版本确认是否正确 2.检查tongweb的 license是不是永久版本&#xff0c;试用期版本到期会停止服务。 3 JVM运行编码配置-根据系统需要配置 3.1-Dfile.encodingUTF-8 编码根据系统需要配置 4. tongweb运行内存大小--根据系统需要配置 4.1一般 …

编译原理--LL(1)分析法实验C++

一、实验项目要求 1.实验目的 根据某一文法编制调试LL&#xff08;1&#xff09;分析程序&#xff0c;以便对任意输入的符号串进行分析。本次实验的目的主要是加深对预测分析LL&#xff08;1&#xff09;分析法的理解。 2.实验要求 对下列文法&#xff0c;用LL&#xff08;…

实际中进行GC调整

调优垃圾回收与任何其他性能调优活动没有什么不同。 您需要确保了解当前的情况和期望的结果&#xff0c;而不是因为对应用程序的随机部分进行调整而产生了诱惑。 通常&#xff0c;只需执行以下过程即可&#xff1a; 陈述您的绩效目标 运行测试 测量 与目标比较 进行更改并…

达梦数据库出现卡慢简单分析点

1.检查是否有锁表 查询锁表&#xff1a;select sess_id,sql_text from v$sessions sess,v$lock lck where sess.trx_idlck.trx_id and lck.blocked1; --查询僵死会话 解锁&#xff1a;根据会话ID&#xff0c;停止会话 sp_close_session(sess_id); 2.根据v$sessions,V$L…

对象的属性

首先要理解的是“实例变量”。 我们在__init__方法中并不是创建了实例变量&#xff0c;我们是添加了一个或者多个属性给实际的对象 在__init__内部 self.x 5和外部 f.x 5没有什么不同。 那么类呢&#xff1f; 1 >>> class Bar(object): 2 pass 3 4 >>>…

hibernate.session.get()方法不能获取表中最新数据解决方式样例

1.A a (A)session.get(A.class, id); sess.createSQLQuery("update A set name where id ").executeUpdate(); A a1 (A)session.get(A.class, id);//a1中获取不到修改后的name值 sess.refresh(a1);//刷新a1对象&#xff0c;取出数据库数据 注&#xff1a;hibern…

hibernate 映射_Hibernate映射集合性能问题

hibernate 映射首先&#xff0c;本文的灵感来自于Burt Beckwith在2011年1月27日于SpringOne 2GX上发表的有关高级GORM –性能&#xff0c;自定义和监视的演讲 。 简而言之&#xff0c; Burt Beckwith讨论了使用映射集合和GORM中的Hibernate 2级缓存的潜在性能问题&#xff0c;以…

SEL selector (二)

SEL消息机制工作原理是什么 引用下面文章&#xff1a; 我们在之前有提到,一个类就像一个 C 结构.NSObject 声明了一个成员变量: isa. 由于 NSObject 是所有类的根类,所以所有的对象都会有一个 isa 的成员变量[公共继承].而该 isa 变量指向该对象的类(图3.15)[类在Objective-C中…

Ext grid 根据行号获取行数据

var storeExt.getCmp(grid_id).store;// var storerowstore.getAt(row_num);//行数据 var phonenumberstorerow.get(phonenumber);//列信息 //------------------------------------------------------------------------- var dataExt.getCmp(grid_id).store.data; var d…

mobile cpu上禁用alpha test的相关总结

因为&#xff0c;每家芯片的特性不同&#xff0c;根据向framebuffer写法的不同&#xff0c;分为tile-based的mobile cpu&#xff0c;如ImgTec PowerVR&#xff0c;ARM Mali&#xff0c;一部分老版本Qualcomm Adreno。还有标准的direct&#xff08;immediate&#xff09;的mobil…

学习笔记_jquery(js)遍历页面标签

$(#selectTable tr).each(function(i){ // 遍历 tr $(this).children(td).each(function(j){ // 遍历td var id $(this).context.id; }); }); //---------------------- $("input[namename1]").each(function(){ //遍历name…

简易分享功能(非第三方)

在做一个新项目时&#xff0c;需要一个新浪和微信的分享功能&#xff0c;起初看到这个需求&#xff0c;感觉没有什么&#xff0c;直接使用第三方比较成熟的分享组件就可以的&#xff0c;比如&#xff1a;jiathis、百度分享组件&#xff0c;这些都可以很轻松并且方便的完成所需要…