ASP.NET創(chuàng)建XML Web服務(wù)全接觸(10)
發(fā)表時間:2024-02-07 來源:明輝站整理相關(guān)軟件相關(guān)文章人氣:
[摘要]和XML Web服務(wù)異步地通訊 和一個XML Web服務(wù)異步通訊遵循被Microsoft.NET Framework其它部分使用的異步設(shè)計模式。然而,在你取得那些細節(jié)之前,重要的是注意一個XML Web服務(wù)不必特意的寫來處理用于異步調(diào)用的異步請求。你使用Wsdl.exe為你的客戶端創(chuàng)建的代理類自...
和XML Web服務(wù)異步地通訊
和一個XML Web服務(wù)異步通訊遵循被Microsoft.NET Framework其它部分使用的異步設(shè)計模式。然而,在你取得那些細節(jié)之前,重要的是注意一個XML Web服務(wù)不必特意的寫來處理用于異步調(diào)用的異步請求。你使用Wsdl.exe為你的客戶端創(chuàng)建的代理類自動地創(chuàng)建用于異步調(diào)用XML Web服務(wù)方法的方法。即使只有一個XML Web服務(wù)方法的同步實現(xiàn)也是這樣的。
.NET Framework異步方法調(diào)用設(shè)計模式
用于調(diào)用異步方法的設(shè)計模式,尤其是用于.NET Framework,針對每個同步方法分別有兩個異步方法。對每個同步方法,都有一個Begin異步方法和一個End異步方法。Begin方法被客戶端調(diào)用來開始方法調(diào)用。也就是說,客戶端指示這個方法來開始處理方法調(diào)用,但是立即返回。End方法被客戶端調(diào)用來取得XML Web服務(wù)方法調(diào)用執(zhí)行的處理結(jié)果。
一個客戶端如何知道何時調(diào)用End方法?.NET Framework定義了兩種方法來實現(xiàn)客戶端判斷其時間。第一種是傳送一個回調(diào)函數(shù)到Begin方法,當(dāng)方法已經(jīng)完成處理的時候調(diào)用。第二個方法是使用WaitHandle類的一個方法來導(dǎo)致客戶端等待方法完成。當(dāng)一個客戶端實現(xiàn)第二個方法,并且調(diào)用Begin方法,返回值不是XML Web服務(wù)方法指定的數(shù)據(jù)類型,而是一個實現(xiàn)IAsyncResult接口的類型。IAsyncResult接口包含一個WaitHandle類型的AsyncWaitHandle屬性,實現(xiàn)支持等待同步對象變?yōu)閹в蠾aitHandle.WaitOne、WaitAny和WaitAll標記的方法。當(dāng)一個同步對象被標記的時候,它指示等待特定的資源的線程可以訪問資源的。如果一個XML Web服務(wù)客戶端使用wait方法僅僅異步地調(diào)用一個XML Web服務(wù)方法,那么它可以調(diào)用WaitOne來等待XML Web服務(wù)方法完成處理。
重要的是注意不管客戶端選擇來與XML Web服務(wù)異步通訊的兩種方法中的哪一種,SOAP消息發(fā)送和接收都與同步通信時吻合。也就是說,只有一個SOAP請求和SOAP響應(yīng)通過網(wǎng)絡(luò)發(fā)送和接收。代理類通過使用一個不同的線程而不是客戶端用來調(diào)用Begin方法的線程來處理SOAP響應(yīng)。因此,客戶端可以繼續(xù)執(zhí)行線程上的其它的工作,而代理類處理接收和操作SOAP響應(yīng)。
實現(xiàn)一個產(chǎn)生異步的方法調(diào)用的XML Web服務(wù)客戶端
用于從使用ASP.NET創(chuàng)建的XML Web服務(wù)客戶端產(chǎn)生一個到XML Web服務(wù)的異步調(diào)用的體系結(jié)構(gòu)被嵌入.NET Framework和由Wsdl.exe構(gòu)造的代理類中。用于異步調(diào)用的設(shè)計模式被.NET Framework定義,代理類提供和一個XML Web服務(wù)異步通信的機制。當(dāng)一個用于XML Web服務(wù)的代理類被使用Wsdl.exe構(gòu)造的時候,有三個方法分別被創(chuàng)建,用于XML Web服務(wù)中的公共XML Web服務(wù)方法。下面的表格描述那三個方法。
代理類中的方法名 描述
。糔ameOfWebServiceMethod> 同步發(fā)送用于名為<NameOfWebServiceMethod>的XML Web服務(wù)方法的消息。
Begin<NameOfWebServiceMethod> 開始與名為<NameOfWebServiceMethod>的XML Web服務(wù)方法的異步消息通信。
End<NameOfWebServiceMethod> 結(jié)束與名為<NameOfWebServiceMethod>的XML Web服務(wù)方法的異步消息通信,從XML Web服務(wù)方法中取得完成的消息。
下面的代碼示例是一個XML Web服務(wù)方法,它可能花費相對長的時間來完成處理。因此,當(dāng)你應(yīng)該設(shè)置你的XML Web服務(wù)客戶端來異步地調(diào)用XML Web服務(wù)方法的時候,它是一個很好的示例。
[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服務(wù)方法。注意BeginFactorize和EndFactorize方法,因為它們被用來與Factorize XML Web服務(wù)方法異步通信。
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服務(wù)方法異步通信。下面的代碼示例說明了如何與一個XML Web服務(wù)方法異步通信,并且使用回調(diào)函數(shù)來取得XML Web服務(wù)方法的結(jié)果。
[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服務(wù)方法異步通信,然后使用一個同步對象來等待處理結(jié)束。
[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是一個需要同步化/線成親和上下文的上下文綁定類,那么回調(diào)被通過上下文分配體系結(jié)構(gòu)來分配。換句話說,相對于它的對這樣的上下文的調(diào)用者,回調(diào)可能異步的執(zhí)行。在方法標記上有單向修飾詞的精確的語義。這指的是任何這樣的方法調(diào)用可能同步地或異步地執(zhí)行,相對于調(diào)用者,并且在執(zhí)行控制返回給它的時候,調(diào)用者不能產(chǎn)生任何關(guān)于完成這樣一個調(diào)用的假設(shè)。
而且,在異步操作完成之前調(diào)用EndInvoke將阻塞調(diào)用者。使用相同的AsyncResult再次調(diào)用它的行為是不確定的。
Cancel方法是一個在過去一段特定時間之后取消方法處理的請求。注意它是一個客戶端的請求,并且最好服務(wù)器對此有所承諾。在接收到方法已經(jīng)被取消的消息之后,客戶端就不必做服務(wù)器是否已經(jīng)停止處理的假設(shè)了。客戶端最好不要破壞資源,例如文件對象,因為服務(wù)器可能仍然需要使用它們。IAsyncResult實例的IsCompleted屬性在服務(wù)器結(jié)束它的處理之后將被設(shè)置為true,不再使用任何客戶端提供的資源。因此,IsCompleted屬性設(shè)置為true之后,客戶端就可以安全的銷毀資源了。