简介
最近我编写了很多智能客户端应用,总结了一些能够使应用程序在后台调用Web Service时不冻结前台界面的异步调用方法。虽然当前.NET Framework本身已经提供了异步调 用的机制,但我发现在Windows应用中这一机制比较难于把握,因为这时你需要正确的控制用 户界面线程处理。
在这篇文章中,我将教给您一种在Windows应用程序中实现异步调 用Web服务的简单方法,通过这一方法,您不用再考虑后台线程与前台界面线程的交互关系了 。
服务代理
Visual Studio .NET会生成较好的Web服务代理类,通过它可以 异步的使用Web服务,但是这个代理类实现的是.NET Framework本身的异步调用机制,如上所 述,这一机制对于Windows应用来说并不十分方便。由于这个原因,我一般不直接使用生成的 代理类,而是在中间增加服务代理类。
服务代理类就是增加了额外功能的类,这些功 能可以帮助客户端程序与Web服务进行交互。服务代理类实现了许多有用的功能,包括数据缓 存,安全身份管理,离线操作支持等等。本文中创建的服务代理类比.NET Framework本身的 普通代理类实现了更简便的异步调用模式。
用户界面线程
应用程序从一个创建和 管理用户界面的线程起始,这一线程被称为用户界面线程。大多数开发者本能的会使用用户 界面线程完成所有的工作,包括进行Web服务调用,远程对象调用,访问数据库等等,大多数 使用和性能方面的问题是由这一不恰当的方法引起的。
问题的本质是你永远不可能精 确的预知访问Web服务,远程对象,或者数据库所需的时间。而且当你在用户界面线程中进行 这类的调用时,用户界面就有可能会产生令人恼怒的冻结。
自然而然的,你会把这一 类的调用放置在一个单独的线程中,但我更进了一步,建议您把所有的非用户界面工作坊制 在一个分离的线程中。我的观点是,用户界面线程只用来管理用户界面,而所有那些你不能 保证良好响应时间的对象调用都应该是异步的,无论是进程内的,跨进程的,还是跨计算机 的。
无论如何,尽量使用户界面线程处理的异步调用模式简单化,我已经实现了一个 与Visual Studio 2005里某个特性类似的简单异步调用模式。作为开始,我们首先解释一下 当前.NET Framework中异步调用模式的工作原理。
.NET异步调用模式
系统生成的 Web服务代理类的每个Web函数都有一个Begin和一个End方法,每个支持.NET Framework异步 调用模式的对象都和这个类似。开始进行异步调用时,客户端调用Begin方法时就立即响应, 或者在建立了访问Web服务的独立线程后马上响应。在这之后的某个时间,当Web服务访问完 成后,客户端再调用End方法。
但客户端如何知道什么时候调用End方法呢?Begin方 法会返回一个IAsyncResult对象,可以帮助你跟踪异步调用的过程,也可以明确的等待后台 线程完成,但如果在用户界面线程中进行这些工作,会降低整个系统的同步性。更好的方法 是,在用户界面进程中注册一个回调函数,当其它工作完成时产生一个自动通知。
让 我们看一段样例代码,在这段代码中,我们从一个Web服务中获取一些客户数据,这些功能通 过Web服务代理类里的GetCustomerData方法完成。我们可以启动这个Web服务调用,并且用以 下代码注册一个回调函数,用来在用户界面线程中产生与应用程序进行交互的功能。
private void SomeUIEvent( object sender, EventArgs e )
{
// Create a callback delegate so we will
// be notified when the call has completed.
AsyncCallback callBack = new
AsyncCallback( CustomerDataCallback );
// Start retrieving the customer data.
_proxy.BeginGetCustomerData( "Joe Bloggs", callBack, null );
}