当添加 Web 引用时,Visual Studio 生成既可以同步也可以异步调用 XML Web services 的代理类。通过使用异步方法,您可以在等待 XML Web services 响应时继续使用调用线程。这使您有效地使用客户端应用程序中现有的线程集,如果客户端是 Web 应用程序,这可能十分关键。XML Web services 不需要特殊的配置来支持异步调用,它也不知道客户端以何种模式调用它,这是因为对于同步调用和异步调用来说,请求和响应消息行为是相同的。客户端异步调用只是使用系统 I/O 完成端口有效地等待服务器的响应。
对于每个同步方法,生成的代理类还包含相应的 Begin 和 End 方法。因此,如果 XML Web services 方法的名称是 ConvertTemperature,代理类中同步方法的名称也是 ConvertTemperature,支持异步调用的其他代理方法是 BeginConvertTemperature 和 EndConvertTemperature。
异步调用 XML Web services 这一操作分为两个步骤。第一步(调用 Begin 方法)启动 XML Web services 调用。第二步(调用 End 方法)完成 XML Web services 调用并返回 XML Web services 响应。
Begin 方法返回 System.Web.Services.Protocols.WebClientAsyncResult 对象。该对象(它实现 System.IAsyncResult)达到两个目的。首先,它提供有关挂起异步调用的状态。例如,IsCompleted 属性指示操作是否已完成。其次,通过将该对象传递给 End 方法,代理可以识别将完成哪个请求。这非常重要,因为您可以同时进行多个异步调用。
有多种方法确定异步 XML Web services 调用何时完成:
WaitHandle 类使客户端可以异步调用并等待以下对象:
如果同时进行多个异步 XML Web services 调用,那么您可能要使用 WaitHandle.WaitAll 方法来阻塞线程,直到所有调用完成为止。如果要在结果到达时对其进行处理,可以使用 WaitHandle.WaitAny 方法。该方法将指示一个操作已经完成并将识别该已完成的操作。
当从 Web 应用程序异步访问 XML Web services 时,使用 WaitHandle 类的方法是首选方法。否则,如果 Web 应用程序中的执行在异步进程调用回调函数之前完成(如上一节所述),那么当原始函数的完成导致 Web 窗体的实例毁坏时,它可能永远不会有机会完成此操作。
如果要中止异步 XML Web services 调用,请将从 Begin 方法返回的 IAsyncResult 转换为 WebClientAsyncResult 并调用其 Abort 方法。
有关更多信息,请参见asp">与 XML Web services 进行异步通信。
使用托管代码中的回调函数异步调用 XML Web services
下面显示的代码来自一个 Windows 应用程序,该应用程序正在访问一个 XML Web services,而该应用程序具有一个对该 XML Web services 的 Web 引用 (Translator),该引用包含代理类 (Service1),而该代理类具有异步调用 XML Web services 的 Begin 方法 (BeginLongProcess) 和完成调用并获得结果的 End 方法 (EndLongProcess)。在此示例中,XML Web services 接受字符串,执行某些耗时的转换,然后返回结果。在启动对 XML Web services 方法的异步调用之后,事件处理程序 button1_Click 将控制返回给客户端。当 XML Web services 返回其结果时,它调用回调函数。
' Visual Basic Private Sub Button1_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles Button1.Click Dim cService As New Translator.Service1() ' cb is essentially a function pointer to ServiceCallback. Dim cb As New AsyncCallback(AddressOf ServiceCallback) ' Call the Begin method of the proxy class to initiate the ' asynchronous call to the XML Web service method. cService.BeginLongProcess(TextBox1.Text, cb, cService) End Sub Public Sub ServiceCallback(ByVal ar As IAsyncResult) Dim cService As Translator.Service1 ' Retrieve the original state for the proxy. cService = ar.AsyncState ' Retrieve results by calling the End method of the proxy class. TextBox2.Text = cService.EndLongProcess(ar) End Sub // C# private void button1_Click(object sender, System.EventArgs e) { Translator.Service1 cService = new Translator.Service1(); // cb is essentially a function pointer to ServiceCallback. AsyncCallback cb = new AsyncCallback(ServiceCallback); // Call the Begin method of the proxy class to initiate the // asynchronous call to the XML Web service method. cService.BeginLongProcess(textBox1.Text, cb, cService); } public void ServiceCallback(IAsyncResult ar) { // Retrieve the original state for the proxy. Translator.Service1 cService = (Translator.Service1)ar.AsyncState; // Retrieve results by calling the End method of the proxy class textBox2.Text = cService.EndLongProcess(ar); }使用托管代码中的 WaitHandle 异步调用 XML Web services
若要访问 XML Web services,您必须创建该代理类的实例,然后与该方法进行交互,就像与类的任何其他实例的方法进行交互一样。
下面显示的代码来自一个 Web 应用程序,该应用程序正在访问一个 XML Web services,而该应用程序具有一个对该 XML Web services 的 Web 引用 (Translator),该引用包含代理类 (Service1),而该代理类具有异步调用 XML Web services 的 Begin 方法 (BeginLongProcess) 和完成调用并获得结果的 End 方法 (EndLongProcess)。在此示例中,XML Web services 接受字符串,执行某些耗时的转换,然后返回结果。在启动对 XML Web services 方法的异步调用之后,客户端应用程序继续一些其他的处理,然后等待 XML Web services 返回。当 XML Web services 返回后,处理将继续。
' Visual Basic Private Sub Button1_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles Button1.Click Dim cService As New Translator.Service1() Dim ar1 As IAsyncResult Dim ar2 As IAsyncResult ' Call the Begin method of the proxy class to initiate the ' asynchronous call to the XML Web service method. ar1 = cService.BeginLongProcess(TextBox1.Text, Nothing, Nothing) ar2 = cService.BeginLongProcess(TextBox3.Text, Nothing, Nothing) '... ' Keep processing. '... Dim wh() As WaitHandle = {ar1.AsyncWaitHandle, ar2.AsyncWaitHandle} ' Waits for both async XML Web service calls to finish. WaitHandle.WaitAll(wh) ' Retrieves the results by calling the End method of the proxy ' class. TextBox2.Text = cService.EndLongProcess(ar1) TextBox4.Text = cService.EndLongProcess(ar2) End Sub // C# private void Button1_Click(object sender, System.EventArgs e) { Translator.Service1 cService = new Translator.Service1(); IAsyncResult ar1 = cService.BeginLongProcess(TextBox1.Text, null, null); IAsyncResult ar2 = cService.BeginLongProcess(TextBox3.Text, null, null); //... // Keep processing. //... WaitHandle[] wh = {ar1.AsyncWaitHandle, ar2.AsyncWaitHandle}; // Waits for both async XML Web service calls to finish. WaitHandle.WaitAll(wh); // Retrieves the results by calling the End method of the proxy // class. TextBox2.Text = cService.EndLongProcess(ar1); TextBox4.Text = cService.EndLongProcess(ar2); }