|
ASP.NET创建XML Web服务全接触(10)
异步Web服务(2) 和XML Web服务异步地通讯
和一个XML Web服务异步通讯遵循被Microsoft.NET Framework其它部分使用的异步设计模式。然而,在你取得那些细节之前,重要的是注重一个XML Web服务不必特意的写来处理用于异步调用的异步哀求。你使用Wsdl.exe为你的客户端创建的代理类自动地创建用于异步调用XML Web服务方式的方式。即使只有一个XML Web服务方式的同步实现也是这样的。
.NET Framework异步方式调用设计模式
用于调用异步方式的设计模式,尤其是用于.NET Framework,针对每个同步方式分别有两个异步方式。对每个同步方式,都有一个Begin异步方式和一个End异步方式。Begin方式被客户端调用来开始方式调用。也就是说,客户端指示这个方式来开始处理方式调用,但是立刻返回。End方式被客户端调用来取得XML Web服务方式调用执行的处理结果。
一个客户端如何知道何时调用End方式?.NET Framework定义了两种方式来实现客户端判定其时间。第一种是传送一个回调函数到Begin方式,当方式已经完成处理的时候调用。第二个方式是使用WaitHandle类的一个方式来导致客户端等待方式完成。当一个客户端实现第二个方式,并且调用Begin方式,返回值不是XML Web服务方式指定的数据类型,而是一个实现IAsyncResult接口的类型。IAsyncResult接口包含一个WaitHandle类型的AsyncWaitHandle属性,实现支持等待同步对象变为带有WaitHandle.WaitOne、WaitAny和WaitAll标记的方式。当一个同步对象被标记的时候,它指示等待特定的资源的线程可以访问资源的。假如一个XML Web服务客户端使用wait方式仅仅异步地调用一个XML Web服务方式,那么它可以调用WaitOne来等待XML Web服务方式完成处理。
重要的是注重不管客户端选择来与XML Web服务异步通讯的两种方式中的哪一种,SOAP消息发送和接收都与同步通信时吻合。也就是说,只有一个SOAP哀求和SOAP响应通过网络发送和接收。代理类通过使用一个不同的线程而不是客户端用来调用Begin方式的线程来处理SOAP响应。因此,客户端可以继承执行线程上的其它的工作,而代理类处理接收和操作SOAP响应。
实现一个产生异步的方式调用的XML Web服务客户端
用于从使用ASP.NET创建的XML Web服务客户端产生一个到XML Web服务的异步调用的体系结构被嵌入.NET Framework和由Wsdl.exe构造的代理类中。用于异步调用的设计模式被.NET Framework定义,代理类提供和一个XML Web服务异步通信的机制。当一个用于XML Web服务的代理类被使用Wsdl.exe构造的时候,有三个方式分别被创建,用于XML Web服务中的公共XML Web服务方式。下面的表格描述那三个方式。
代理类中的方式名 描述
<NameOfWebServiceMethod> 同步发送用于名为<NameOfWebServiceMethod>的XML Web服务方式的消息。
Begin<NameOfWebServiceMethod> 开始与名为<NameOfWebServiceMethod>的XML Web服务方式的异步消息通信。
End<NameOfWebServiceMethod> 结束与名为<NameOfWebServiceMethod>的XML Web服务方式的异步消息通信,从XML Web服务方式中取得完成的消息。
下面的代码示例是一个XML Web服务方式,它可能花费相对长的时间来完成处理。因此,当你应该设置你的XML Web服务客户端来异步地调用XML Web服务方式的时候,它是一个很好的示例。
[C#] <%@ WebService Language=\"C#\" Class=\"PrimeFactorizer\" %>
using System; using System.Collections; using System.Web.Services;
class PrimeFactorizer {
[WebMethod] public long[] Factorize(long factorizableNum){ ArrayList outList = new ArrayList(); long i = 0; int j; try{ long Check = factorizableNum;
//Go through every possible integer //factor between 2 and factorizableNum / 2. //Thus, for 21, check between 2 and 10. for (i = 2; i < (factorizableNum / 2); i++){ while(Check % i == 0){ outList.Add(i); Check = (Check/i); } } //Double-check to see how many prime factors have been added. //If none, add 1 and the number. j = outList.Count; if (j == 0) { outList.Add(1); outList.Add(factorizableNum); } j = outList.Count;
//Return the results and //create an array to hold them. long[] primeFactor = new long[j]; for (j = 0; j < outList.Count; j++){ //Pass the values one by one, making sure //to convert them to type ulong. primeFactor[j] = Convert.ToInt64(outList[j]); } return primeFactor; } catch (Exception) { return null; } } }
[Visual Basic] <%@ WebService Class=\"PrimeFactorizer\" Language=\"VB\" %> Imports System Imports System.Collections Imports System.Web.Services
Public Class PrimeFactorizer <WebMethod> _ Public Function Factorize(factorizableNum As Long) As Long() Dim outList As New ArrayList() Dim i As Long = 0 Dim j As Integer Try Dim Check As Long = factorizableNum
\\\'Go through every possible integer \\\'factor between 2 and factorizableNum / 2. \\\'Thus, for 21, check between 2 and 10. For i = 2 To CLng(factorizableNum / 2) - 1 While Check Mod i = 0 outList.Add(i) Check = CLng(Check / i) End While Next i \\\'Double-check to see how many prime factors have been added. \\\'If none, add 1 and the number. j = outList.Count If j = 0 Then outList.Add(1) outList.Add(factorizableNum) End If j = outList.Count
\\\'Return the results and \\\'create an array to hold them. Dim primeFactor(j - 1) As Long For j = 0 To outList.Count - 1 \\\'Pass the values one by one, making sure \\\'to convert them to type ulong. primeFactor(j) = CLng(outList(j)) Next j Return primeFactor Catch Return Nothing End Try End Function End Class |
下面的代码示例是一个Wsdl.exe生成的代理类的一部分,用于上述XML Web服务方式。注重BeginFactorize和EndFactorize方式,因为它们被用来与Factorize XML Web服务方式异步通信。
public class PrimeFactorizer : System.Web.Services.Protocols.SoapHttpClientProtocol {
public long[] Factorize(long factorizableNum) { object[] results = this.Invoke(\"Factorize\", new object[] { factorizableNum}); return ((long[])(results[0])); }
public System.IAsyncResult BeginFactorize(long factorizableNum, System.AsyncCallback callback, object asyncState) { return this.BeginInvoke(\"Factorize\", new object[] { factorizableNum}, callback, asyncState); }
public long[] EndFactorize(System.IAsyncResult asyncResult) { object[] results = this.EndInvoke(asyncResult); return ((long[])(results[0])); } } |
有两个方式用来和XML Web服务方式异步通信。下面的代码示例说明了如何与一个XML Web服务方式异步通信,并且使用回调函数来取得XML Web服务方式的结果。
[C#] using System; using System.Runtime.Remoting.Messaging; using MyFactorize;
class TestCallback { public static void Main(){ long factorizableNum = 12345; PrimeFactorizer pf = new PrimeFactorizer();
//Instantiate an AsyncCallback delegate to use as a parameter //in the BeginFactorize method. AsyncCallback cb = new AsyncCallback(TestCallback.FactorizeCallback);
// Begin the Async call to Factorize, passing in our // AsyncCalback delegate and a reference // to our instance of PrimeFactorizer. IAsyncResult ar = pf.BeginFactorize(factorizableNum, cb, pf);
// Keep track of the time it takes to complete the async call // as the call proceeds. int start = DateTime.Now.Second; int currentSecond = start; while (ar.IsCompleted == false){ if (currentSecond < DateTime.Now.Second) { currentSecond = DateTime.Now.Second; Console.WriteLine(\"Seconds Elapsed...\" + (currentSecond - start).ToString() ); } } // Once the call has completed, you need a method to ensure the // thread executing this Main function // doesn\\\'t complete prior to the call-back function completing. Console.Write(\"Press Enter to quit\"); int quitchar = Console.Read(); } // Set up a call-back function that is invoked by the proxy class // when the asynchronous operation completes. public static void FactorizeCallback(IAsyncResult ar) { // You passed in our instance of PrimeFactorizer in the third // parameter to BeginFactorize, which is accessible in the // AsyncState property. PrimeFactorizer pf = (PrimeFactorizer) ar.AsyncState; long[] results;
// Get the completed results. results = pf.EndFactorize(ar);
//Output the results. Console.Write(\"12345 factors into: \"); int j; for (j = 0; j<results.Length;j++){ if (j == results.Length - 1) Console.WriteLine(results[j]); else Console.Write(results[j] + \", \"); } } }
[Visual Basic] Imports System Imports System.Runtime.Remoting.Messaging Imports MyFactorize
Public Class TestCallback Public Shared Sub Main() Dim factorizableNum As Long = 12345 Dim pf As PrimeFactorizer = new PrimeFactorizer()
\\\'Instantiate an AsyncCallback delegate to use as a parameter \\\' in the BeginFactorize method. Dim cb as AsyncCallback cb = new AsyncCallback(AddressOf TestCallback.FactorizeCallback)
\\\' Begin the Async call to Factorize, passing in the \\\' AsyncCallback delegate and a reference to our instance \\\' of PrimeFactorizer. Dim ar As IAsyncResult = pf.BeginFactorize(factorizableNum, cb, pf)
\\\' Keep track of the time it takes to complete the async call as \\\' the call proceeds. Dim start As Integer = DateTime.Now.Second Dim currentSecond As Integer = start Do while (ar.IsCompleted = false) If (currentSecond < DateTime.Now.Second) Then currentSecond = DateTime.Now.Second Console.WriteLine(\"Seconds Elapsed...\" + (currentSecond - start).ToString() ) End If Loop
\\\' Once the call has completed, you need a method to ensure the \\\' thread executing this Main function \\\' doesn\\\'t complete prior to the callback function completing. Console.Write(\"Press Enter to quit\") Dim quitchar As Integer = Console.Read() End Sub
\\\' Set up the call-back function that is invoked by the proxy \\\' class when the asynchronous operation completes. Public Shared Sub FactorizeCallback(ar As IAsyncResult)
\\\' You passed in the instance of PrimeFactorizer in the third \\\' parameter to BeginFactorize, which is accessible in the \\\' AsyncState property.
Dim pf As PrimeFactorizer = ar.AsyncState Dim results() as Long
\\\' Get the completed results. results = pf.EndFactorize(ar)
\\\'Output the results. Console.Write(\"12345 factors into: \") Dim j as Integer For j = 0 To results.Length - 1 If j = (results.Length - 1) Then Console.WriteLine(results(j) ) Else Console.Write(results(j).ToString + \", \") End If Next j End Sub End Class |
下面的代码示例说明了如何与一个XML Web服务方式异步通信,然后使用一个同步对象来等待处理结束。
[C#] // -----------------------------------------------------------------------// Async Variation 2. // Asynchronously invoke the Factorize method, //without specifying a call back. using System; using System.Runtime.Remoting.Messaging; // MyFactorize, is the name of the namespace in which the proxy class is // a member of for this sample. using MyFactorize;
class TestCallback { public static void Main(){ long factorizableNum = 12345; PrimeFactorizer pf = new PrimeFactorizer();
// Begin the Async call to Factorize. IAsyncResult ar = pf.BeginFactorize(factorizableNum, null, null);
// Wait for the asynchronous operation to complete. ar.AsyncWaitHandle.WaitOne();
// Get the completed results. long[] results; results = pf.EndFactorize(ar);
//Output the results. Console.Write(\"12345 factors into: \"); int j; for (j = 0; j<results.Length;j++){ if (j == results.Length - 1) Console.WriteLine(results[j]); else Console.Write(results[j] + \", \"); } } }
[Visual Basic] Imports System Imports System.Runtime.Remoting.Messaging Imports MyFactorize \\\' Proxy class namespace
Public Class TestCallback Public Shared Sub Main() Dim factorizableNum As Long = 12345 Dim pf As PrimeFactorizer = new PrimeFactorizer()
\\\' Begin the Async call to Factorize. Dim ar As IAsyncResult = pf.BeginFactorize(factorizableNum, Nothing, Nothing)
\\\' Wait for the asynchronous operation to complete. ar.AsyncWaitHandle.WaitOne()
\\\' Get the completed results. Dim results() as Long results = pf.EndFactorize(ar)
\\\'Output the results. Console.Write(\"12345 factors into: \") Dim j as Integer For j = 0 To results.Length - 1 If j = (results.Length - 1) Then Console.WriteLine(results(j) ) Else Console.Write(results(j).ToString + \", \") End If Next j End Sub End Class |
注重:假如FactorizeCallback是一个需要同步化/线成亲和上下文的上下文绑定类,那么回调被通过上下文分配体系结构来分配。换句话说,相对于它的对这样的上下文的调用者,回调可能异步的执行。在方式标记上有单向修饰词的精确的语义。这指的是任何这样的方式调用可能同步地或异步地执行,相对于调用者,并且在执行控制返回给它的时候,调用者不能产生任何关于完成这样一个调用的假设。 而且,在异步操作完成之前调用EndInvoke将阻塞调用者。使用一样的AsyncResult再次调用它的行为是不确定的。
Cancel方式是一个在过去一段特定时间之后取消方式处理的哀求。注重它是一个客户端的哀求,并且最好服务器对此有所承诺。在接收到方式已经被取消的消息之后,客户端就不必做服务器是否已经停止处理的假设了。客户端最好不要破坏资源,例如文件对象,因为服务器可能仍旧需要使用它们。IAsyncResult实例的IsCompleted属性在服务器结束它的处理之后将被设置为true,不再使用任何客户端提供的资源。因此,IsCompleted属性设置为true之后,客户端就可以安全的销毁资源了。
返回类别: 教程 上一教程: URTracker 2.11版 license验证原理剖析 下一教程: ASP.NET 打造互联网未来空间站(2)
您可以阅读与"ASP.NET创建XML Web服务全接触(10)"相关的教程: · ASP.NET创建XML Web服务全接触(11) · ASP.NET创建XML Web服务全接触(2) · ASP.NET创建XML Web服务全接触(3) · ASP.NET创建XML Web服务全接触(1) · ASP.NET创建XML Web服务全接触(6)
|