异步调用WEBSERVICE
Web 服务描述语言工具 (Wsdl.exe) 生成客户端代理类来访问指定的 Web 服务时,会为该代理类提供与每个 Web 服务方法进行异步通信的两种机制。第一种机制是 Begin/End 模式。第二种机制是在 .NET Framework 2.0 版中提供的事件驱动的异步编程模式。
Begin/End 调用模式
Wsdl.exe 为 Web 服务中发布的每项操作自动创建三个方法(ASP.NET 中的 Web 服务方法)。一个方法针对同步访问;另外两个方法针对异步访问。即使该 Web 服务方法只有一个同步实现也不例外。下表对这三个方法进行了说明:
代理类中方法的名称
| 说明
|
<NameOfWebServiceMethod> | 为名为 <NameOfWebServiceMethod> 的 Web 服务方法同步发送消息。 |
Begin<NameOfWebServiceMethod> | 开始与名为 <NameOfWebServiceMethod> 的 Web 服务方法的异步消息通信。客户端指示 Begin 方法开始对服务调用进行处理,但立即返回。返回值不是 Web 服务方法指定的数据类型,而是实现 IAsyncResult 接口的类型。 |
End <NameOfWebServiceMethod> | 结束与名为 <NameOfWebServiceMethod> 的 Web 服务方法的异步消息通信,返回的值是 Web 服务方法调用的结果。 |
Begin 和 End 方法均遵循 .NET Framework 异步设计模式的命名约定。该设计模式规定每种同步方法有两种如此命名的异步方法。
使用 Begin/End 模式实现进行异步方法调用的 Web 服务客户端
客户端如何知道何时调用 End 方法呢?根据 .NET Framework 的定义,有两种方法可以使客户端确定这一点:
·
等待方法:使用 WaitHandle 类的方法之一使客户端等待方法完成。
·
回调方法:向 Begin 方法传递一个回调函数,在该方法完成处理后再调用该函数来检索结果。
注意:无论客户端选择两种方法中的哪一种与 Web 服务进行异步通信,收发的 SOAP 消息都与通过同步代理方法生成的 SOAP 消息相同。也就是说,仍然只有一个 SOAP 请求和 SOAP 响应通过网络发送和接收。代理类通过使用与客户端调用 Begin 方法时使用的线程不同的线程来处理 SOAP 响应,从而实现该目的。因此,在代理类接收和处理 SOAP 响应时,客户端可以在其线程上继续执行其他工作。
使用 Begin/End 模式的等待方法
WaitHandle 类实现下列支持等待同步对象得到信号通知的方法:WaitOne、WaitAny 和 WaitAll。当同步对象得到信号通知时,表示等待指定资源的线程此时可以访问该资源了。Web 服务客户端通过 Begin 方法返回的 IAsyncResult 对象的 AsyncWaitHandle 属性,来访问 WaitHandle 对象。
具体做法:
1、
Web 服务客户端调用所生成的代理类的 Begin 方法。
IAsyncResult ar = pf.BeginFactorize(factorizableNum, null, null);
2、
Web 服务客户端通过返回的 IAsyncResult 的 AsyncWaitHandle 属性来访问 WaitHandle 对象。
ar.AsyncWaitHandle.WaitOne()
3、
等待方法返回后,客户端调用 End 方法来获取结果。
results = pf.EndFactorize(ar);
使用 Begin/End 模式的回调方法
具体做法:
- 定义实现 AsyncCallback 委托的回调函数。
public static void FactorizeCallback(IAsyncResult ar)
AsyncCallback cb = new AsyncCallback(TestCallback.FactorizeCallback);
-
调用 Begin 方法,将回调函数作为第二个参数传递,将提供状态的对象(在本示例中是 PrimeFactorizer 的客户端实现)作为第三个参数传递。
IAsyncResult ar = pf.BeginFactorize(factorizableNum, cb, pf);
-
在 Begin 方法返回的 IAsyncResult 上检查 IsCompleted 属性。如果客户端已收到服务器的响应,该值将设置为 true。
-
在回调函数中访问状态对象。IAsyncState 参数的 AsyncState 属性将该对象作为第三个参数传递给 Begin 方法。
PrimeFactorizer pf = (PrimeFactorizer) ar.AsyncState;
-
在回调函数中,对上一步中获取的状态对象调用 End 方法。
long[] results = pf.EndFactorize(ar);
使用事件驱动的异步模式的异步 Web 服务客户端
Web 服务代理类中的每个 Web 方法都具有一个异步的对应版本。代理类自动生成每个 Web 方法的异步方法和对应事件。当异步方法被调用时,它将在另一个线程上执行,并在返回时引发对应的事件。您可以为异步方法的对应事件创建一个处理程序,从而 在它返回时执行代码。
此模型可以简化生成多线程应用程序的过程,因为您不必自己实现复杂的多线程代码。
具体做法:
1、
创建MethodCompleted 事件。
private void HelloWorldCompleted(Object sender,
localhost.HelloWorldCompletedEventArgs Completed)
{
// Insert code to implement the method here
}
2、
向该事件的处理程序列表添加 MethodCompleted 事件处理程序。
myWebService.HelloWorldCompleted += new localhost.HelloWorldCompletedEventHandler(HelloWorldCompleted);
3、
使用该方法的 MethodAsync 形式调用 Web 方法.
HelloWorldAsync();
注意,在net3.0中请将 ASP.NET 页面@ Page 指令中的Async设置为 true。
示例代码[环境VS2008+NET3.5]
1、
webservice页WebService.asmx示例代码。
using
System;
using
System.Collections;
using
System.Linq;
using
System.Web;
using
System.Web.Services;
using
System.Web.Services.Protocols;
using
System.Xml.Linq;
using
System.Threading;


/**/
/// <summary>
/// Summary description for WebService
/// </summary>
[WebService(Namespace
=
"
http://tempuri.org/
"
)]
[WebServiceBinding(ConformsTo
=
WsiProfiles.BasicProfile1_1)]
//
To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
//
[System.Web.Script.Services.ScriptService]
public
class
WebService : System.Web.Services.WebService

...
{

public WebService()

...{
//Uncomment the following line if using designed components
//InitializeComponent();
}

[WebMethod]
public string HelloWorld()

...{
Thread.Sleep(2000); //停留2秒.
return "Hello World";
}

}

2、
webPage页WSTest.aspx
a.
ASPX
<%
@ Page Language
=
"
C#
"
AutoEventWireup
=
"
true
"
Async
=
"
true
"
CodeFile
=
"
WSTest.aspx.cs
"
Inherits
=
"
WSTest
"
%>

<!
DOCTYPE html PUBLIC
"
-//W3C//DTD XHTML 1.0 Transitional//EN
"
"
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd
"
>

<
html xmlns
=
"
http://www.w3.org/1999/xhtml
"
>
<
head runat
=
"
server
"
>
<
title
>
异步调用WEBSERVICE示例代码
</
title
>
</
head
>
<
body
>
<
form id
=
"
form1
"
runat
=
"
server
"
>
<
div
>
<
asp:Button ID
=
"
EventDriveButton
"
runat
=
"
server
"
Text
=
"
事件驱动的异步模式
"
onclick
=
"
EventDriveButton_Click
"
/>
&
nbsp;
<
asp:Button ID
=
"
BeginEndWaitButton
"
runat
=
"
server
"
Text
=
"
Begin/End 模式等待技术
"
onclick
=
"
BeginEndWaitButton_Click
"
/>
&
nbsp;
<
asp:Button ID
=
"
BeginEndCallBackButton
"
runat
=
"
server
"
Text
=
"
Begin/End 模式回调技术
"
onclick
=
"
BeginEndCallBackButton_Click
"
/>
</
div
>
</
form
>
</
body
>
</
html
>
b.
CS
using
System;
using
System.Collections;
using
System.Configuration;
using
System.Data;
using
System.Linq;
using
System.Web;
using
System.Web.Security;
using
System.Web.UI;
using
System.Web.UI.HtmlControls;
using
System.Web.UI.WebControls;
using
System.Web.UI.WebControls.WebParts;
using
System.Xml.Linq;
using
System.Threading;
using
LocalService;
public
partial
class
WSTest : System.Web.UI.Page

...
{
protected void Page_Load(object sender, EventArgs e)

...{
}

/**//// <summary>
/// 事件驱动的异步模式的异步
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void EventDriveButton_Click(object sender, EventArgs e)

...{
Response.Write("事件驱动的异步模式的异步 <BR>");
LocalService.WebService localService = new LocalService.WebService(); //创建代理类对象。

localService.HelloWorldCompleted += new LocalService.HelloWorldCompletedEventHandler((o, a) => ...{ Response.Write(string.Format("完成时间:{0}。 结果{1}<Br>", DateTime.Now.ToString("mm:ss.ffff"), a.Result)); });//创建事件。写结果与运行事件
Response.Write(string.Format("开始调用时间:{0}<Br>", DateTime.Now.ToString("mm:ss.ffff")));//开始调用事件
localService.HelloWorldAsync();//异步调用
Response.Write(string.Format("调用结束时间:{0}<Br>", DateTime.Now.ToString("mm:ss.ffff")));
Thread.Sleep(4000);//等待异步操作完成
}

/**//// <summary>
/// 使用 Begin/End 模式的等待技术
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void BeginEndWaitButton_Click(object sender, EventArgs e)

...{
LocalService.WebService localService = new LocalService.WebService(); //创建代理类对象。
Response.Write("Begin/End 模式的等待技术<BR>");
Response.Write(string.Format("开始调用时间:{0}<Br>", DateTime.Now.ToString("mm:ss.ffff")));//开始调用事件

IAsyncResult ar = localService.BeginHelloWorld(s => ...{ }, null);
Response.Write(string.Format("调用结束时间:{0}<Br>", DateTime.Now.ToString("mm:ss.ffff")));
ar.AsyncWaitHandle.WaitOne();
string result = localService.EndHelloWorld(ar);
Response.Write(string.Format("完成时间:{0}。 结果{1}<Br>", DateTime.Now.ToString("mm:ss.ffff"), result));
}

/**//// <summary>
/// 使用 Begin/End 模式的回调技术
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void BeginEndCallBackButton_Click(object sender, EventArgs e)

...{
Response.Write("Begin/End 模式的回调技术<BR>");
LocalService.WebService localService = new LocalService.WebService(); //创建代理类对象。
Response.Write(string.Format("开始调用时间:{0}<Br>", DateTime.Now.ToString("mm:ss.ffff")));//开始调用事件
IAsyncResult ar = localService.BeginHelloWorld(helloWorldCallBack, localService);
Response.Write(string.Format("调用结束时间:{0}<Br>", DateTime.Now.ToString("mm:ss.ffff")));

while (!ar.IsCompleted) ...{ }//空循环等待完成
}
private void helloWorldCallBack(IAsyncResult ar)

...{
LocalService.WebService ws = (LocalService.WebService)ar.AsyncState;
string result= ws.EndHelloWorld(ar);
Response.Write(string.Format("完成时间:{0}。 结果{1}<Br>", DateTime.Now.ToString("mm:ss.ffff"), result));
}
}
感谢浏览,欢迎评论,转载请保留作者! http://blog.youkuaiyun.com/Wgf2006/