位置:海鸟网 > IT > ASP.NET >

异步访问托管代码中的 XML Web services

当添加 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 调用何时完成:

  • 第一种方法是向 Begin 方法提供回调委托。在 XML Web services 返回其响应之后,线程将从线程池调用回调;这很可能是一个与用来调用 Begin 方法的线程不同的线程。通常,将在该回调中调用 End 方法。因为回调功能在等待响应时不阻塞线程,所以使用回调是管理线程使用的最有效的方法。
  • 第二种方法是使用 IAsyncResult.AsyncWaitHandle 对象的一种 WaitHandle 方法进行等待。当使用 WaitHandle 类的方法时,客户端还可以指定超时,在超时之后,它将放弃等待从它调用的 XML Web services 返回结果。
  • 第三种方法是轮询 IAsyncResult.IsCompleted 的值。当该属性返回 true 时,XML Web services 响应可用。
  • 第四种方法是仅仅直接调用 End 方法。因为该方法使用 IAsyncResult.AsyncWaitHandle,所以在异步操作完成之前,该方法将不返回。
  • WaitHandle 类使客户端可以异步调用并等待以下对象:

  • 单个 XML Web services (WaitHandle.WaitOne),
  • 多个 XML Web services 中的第一个 (WaitHandle.WaitAny),或
  • 多个 XML Web services 中的所有服务 (WaitHandle.WaitAll) 以返回结果。
  • 如果同时进行多个异步 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

  • 创建要从其中访问 XML Web services 的应用程序。该应用程序甚至可以是另一个 XML Web services。
  • 为应用程序将与之交互的 XML Web services 添加 Web 引用。有关说明,请参见asp">添加和移除 Web 引用。
  • 实现回调函数。回调函数包含对 XML Web services 方法的 End 方法的调用。
  • 在要从其中访问 XML Web services 的客户端代码中创建代理对象的实例。
  • 调用 XML Web services 方法的 Begin 方法。
  • 在客户端应用程序中继续进行任何其他的处理。
  • 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 的应用程序。该应用程序甚至可以是另一个 XML Web services。
  • 为应用程序将与之交互的 XML Web services 添加 Web 引用。当添加 Web 引用时,Visual Studio 将创建代理类,该代理类包含用于访问该 XML Web services 的每个公开方法的方法。有关说明,请参见asp">添加和移除 Web 引用。

    若要访问 XML Web services,您必须创建该代理类的实例,然后与该方法进行交互,就像与类的任何其他实例的方法进行交互一样。

  • 包括命名空间 System.Threading。您将需要该命名空间来访问 WaitHandle 类。
  • 在要从其中访问 XML Web services 的客户端代码中创建代理对象的实例。
  • 通过调用 XML Web services 方法的 Begin 方法,创建到 AsyncResult 的接口,它返回实现 IAsyncResult 接口的类型。
  • 在客户端应用程序中继续进行任何其他的处理。
  • 当处于需要来自 XML Web services 的结果这种情况时,使用 WaitHandle 来暂停处理,等待结果。
  • 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); }