建立非同步 XML Web Service 方法
若要改善 XML Web Service 方法的效能 (這些方法叫用阻檔其執行緒的長時間執行方法),您應該考慮將它們公開為非同步 XML Web Service 方法。實作非同步 XML Web Service 方法可讓該執行緒傳回至執行區集區時,執行其他程式碼。如此可使得執行緒集區除了限制的執行緒數目外再多執行一個,加強系統的整體效能和延展性 (Scalability)。
一般來說,XML Web Service 方法會呼叫執行 I/O 作業的方法,是非同步實作的好方法。這類方法的範例包括與其他 XML Web Service 通訊、存取遠端資料庫、執行網路 I/O 和讀取及寫入大型檔案的方法。這些方法全在硬體的執行上花費大量的時間,因此阻斷了執行緒執行 XML Web Service 方法。如果 XML Web Service 方法非同步實作,這個執行緒即可釋放出來以執行其他程式碼。
無論 XML Web Service 方法是否非同步實作,用戶端都可以非同步與其進行通訊。非同步通訊會公開至用 Web 服務描述語言 (WSDL.EXE) 工具所產生的 Proxy 類別內的 .NET 用戶端,即使同步實作 XML Web Service 方法也是一樣。Proxy 類別包含 Begin 和 End 方法,可以用來非同步與每個 XML Web Service 方法通訊。因此,非同步或同步實作 XML Web Service 方法應該根據效能來決定。
**注意 **實作非同步 XML Web Service 方法對用戶端與裝載 XML Web Service 的伺服器之間的 HTTP 連接並沒有影響。HTTP 連接不會關閉也不會共用。
若要實作非同步 XML Web Service 方法
非同步 XML Web Service 方法的實作遵循 .NET Framework 非同步設計模式
將同步的 XML Web Service 方法分隔成兩種方法;每個都具有相同的基底名稱 - 一個從 Begin 開始而另一個從 End 開始。
Begin 方法的參數清單包含所有的 in 和 by reference 參數,因為方法的功能結尾附加了這兩個參數。
- By reference 參數列出為 in 參數。
- 倒數第二個參數必須是 AsyncCallback。AsyncCallback 參數允許用戶端提供委派 (Delegate),在方法完成時叫用。當非同步 XML Web Service 方法呼叫另一個非同步方法時,這個參數可以傳遞到該方法的倒數第二個參數。
- 最後一個參數是 Object。Object 參數允許呼叫端對方法提供狀態資訊。當非同步 XML Web Service 方法呼叫另一個非同步方法時,這個參數可以傳遞到該方法的最後一個參數。
- 傳回值必須是 IAsyncResult 型別。
下列程式碼範例為 Begin 方法,其具有方法功能專屬的 String 參數。
[WebMethod] public IAsyncResult BeginGetAuthorRoyalties(String Author, AsyncCallback callback, object asyncState) [Visual Basic] <WebMethod()> _ Public Function BeginGetAuthorRoyalties(ByVal Author As String, _ ByVal callback As AsyncCallback, ByVal asyncState As Object) _ As IAsyncResult
End 方法的參數清單由 IAsyncResult 組成,其後跟隨方法之功能專屬的任何 out 和 by reference 參數。
- 傳回值型別與同步 XML Web Service 方法的傳回值型別相同。
- By reference 參數列出為 out 參數。
下列程式碼範例為 End 方法,其傳回
AuthorRoyalties
使用者定義型別。[WebMethod] public AuthorRoyalties EndGetAuthorRoyalties(IAsyncResult asyncResult) [Visual Basic] <WebMethod()> _ Public Function EndGetAuthorRoyalties(ByVal asyncResult As _ IAsyncResult) As AuthorRoyalties
下列程式碼範例是非同步 XML Web Service 方法,可與另一個 XML Web Service 方法進行非同步通訊。
using System; using System.Web.Services; [WebService(Namespace="https://www.contoso.com/")] public class MyService : WebService { public RemoteService remoteService; public MyService() { // Create a new instance of proxy class for // the XML Web service to be called. remoteService = new RemoteService(); } // Define the Begin method. [WebMethod] public IAsyncResult BeginGetAuthorRoyalties(String Author, AsyncCallback callback, object asyncState) { // Begin asynchronous communictation with a different XML Web // service. return remoteService.BeginReturnedStronglyTypedDS(Author, callback,asyncState); } // Define the End method. [WebMethod] public AuthorRoyalties EndGetAuthorRoyalties(IAsyncResult asyncResult) { // Return the asynchronous result from the other XML Web service. return remoteService.EndReturnedStronglyTypedDS(asyncResult); } } [Visual Basic] Imports System.Web.Services <WebService(Namespace:="https://www.contoso.com/")> _ Public Class MyService Inherits WebService Public remoteService As RemoteService Public Sub New() MyBase.New() ' Create a new instance of proxy class for ' the XML Web service to be called. remoteService = New RemoteService() End Sub ' Define the Begin method. <WebMethod()> _ Public Function BeginGetAuthorRoyalties(ByVal Author As String, _ ByVal callback As AsyncCallback, ByVal asyncState As Object) _ As IAsyncResult ' Begin asynchronous communictation with a different XML Web ' service. Return remoteService.BeginReturnedStronglyTypedDS(Author, _ callback, asyncState) End Function ' Define the End method. <WebMethod()> _ Public Function EndGetAuthorRoyalties(ByVal asyncResult As _ IAsyncResult) As AuthorRoyalties ' Return the asynchronous result from the other XML Web service. Return remoteService.EndReturnedStronglyTypedDS(asyncResult) End Function End Class
下列程式碼示範在 XML Web Service 方法進行一個以上非同步呼叫且呼叫必須依序執行時,如何鏈結非同步呼叫。BeginGetAuthorRoyalties
方法進行非同步呼叫以決定傳遞的作者是否有效,然後設定名為 AuthorRoyaltiesCallback
的立即回呼 (Callback) 來接收結果。接著該立即回呼會非同步呼叫以取得該作者的版稅 (如果這個作者是有效的)。
using System.Web.Services;
using System.Data;
using System;
// This imports the proxy class for the XML Web services
// that the sample communicates with.
using AsyncWS.localhost;
namespace AsyncWS
{
[WebService(Namespace="https://www.contoso.com/")]
public class MyService : System.Web.Services.WebService
{
public RemoteService remoteService;
public MyService()
{
remoteService = new RemoteService();
}
[WebMethod]
public IAsyncResult BeginGetAuthorRoyalties(String Author,
AsyncCallback callback, Object asyncState)
{
// Saves the current state for the call that gets the author's
// royalties.
AsyncStateChain state = new AsyncStateChain();
state.originalState = asyncState;
state.Author = Author;
state.originalCallback = callback;
// Creates an intermediary callback.
AsyncCallback chainedCallback = new
AsyncCallback(AuthorRoyaltiesCallback);
return remoteService.BeginGetAuthors(chainedCallback,state);
}
// Intermediate method to handle chaining the
// asynchronous calls.
public void AuthorRoyaltiesCallback(IAsyncResult ar)
{
AsyncStateChain state = (AsyncStateChain)ar.AsyncState;
RemoteService rs = new RemoteService();
// Gets the result from the call to GetAuthors.
Authors allAuthors = rs.EndGetAuthors(ar);
Boolean found = false;
// Verifies that the requested author is valid.
int i = 0;
DataRow row;
while (i < allAuthors.authors.Rows.Count && !found)
{
row = allAuthors.authors.Rows[i];
if (row["au_lname"].ToString() == state.Author)
{
found = true;
}
i++;
}
if (found)
{
AsyncCallback cb = state.originalCallback;
// Calls the second XML Web service, because the author is
// valid.
rs.BeginReturnedStronglyTypedDS(state.Author,cb,state);
}
else
{
// Cannot throw the exception in this function or the XML Web
// service will hang. So, set the state argument to the
// exception and let the End method of the chained XML Web
// service check for it.
ArgumentException ex = new ArgumentException(
"Author does not exist.","Author");
AsyncCallback cb = state.originalCallback;
// Call the second XML Web service, setting the state to an
// exception.
rs.BeginReturnedStronglyTypedDS(state.Author,cb,ex);
}
}
[WebMethod]
public AuthorRoyalties EndGetAuthorRoyalties(IAsyncResult
asyncResult)
{
// Check whehter the first XML Web service threw an exception.
if (asyncResult.AsyncState is ArgumentException)
throw (ArgumentException) asyncResult.AsyncState;
else
return remoteService.EndReturnedStronglyTypedDS(asyncResult);
}
}
// Class to wrap the callback and state for the intermediate
// asynchronous operation.
public class AsyncStateChain
{
public AsyncCallback originalCallback;
public Object originalState;
public String Author;
}
}
[Visual Basic]
Imports System.Web.Services
Imports System.Data
Imports System
' This imports the proxy class for the XML Web services
' that the sample communicates with.
Imports AsyncWS_VB.localhost
Namespace AsyncWs
<WebService(Namespace:="https://www.contoso.com/")> _
Public Class MyService
Inherits WebService
Public remoteService As remoteService
Public Sub New()
MyBase.New()
remoteService = New localhost.RemoteService()
End Sub
' Defines the Begin method.
<WebMethod()> _
Public Function BeginGetAuthorRoyalties(ByVal Author As String, _
ByVal callback As AsyncCallback, ByVal asyncState As Object) _
As IAsyncResult
' Saves the current state for the call that gets the author's
' royalties.
Dim state As AsyncStateChain = New AsyncStateChain()
state.originalState = asyncState
state.Author = Author
state.originalCallback = callback
' Creates an intermediary callback.
Dim chainedCallback As AsyncCallback = New AsyncCallback( _
AddressOf AuthorRoyaltiesCallback)
' Begin asynchronous communictation with a different XML Web
' service.
Return remoteService.BeginGetAuthors(chainedCallback, state)
End Function
' Intermediate method to handle chaining the asynchronous calls.
Public Sub AuthorRoyaltiesCallback(ByVal ar As IAsyncResult)
Dim state As AsyncStateChain = CType(ar.AsyncState, _
AsyncStateChain)
Dim rs As RemoteService = New RemoteService()
' Gets the result from the call to GetAuthors.
Dim allAuthors As Authors = rs.EndGetAuthors(ar)
Dim found As Boolean = False
' Verifies that the requested author is valid.
Dim i As Integer = 0
Dim row As DataRow
While (i < allAuthors.authors.Rows.Count And (Not found))
row = allAuthors.authors.Rows(i)
If (row("au_lname").ToString() = state.Author) Then
found = True
End If
i = i + 1
End While
If (found) Then
Dim cb As AsyncCallback = state.originalCallback
' Calls the second XML Web service, because the author is
' valid.
rs.BeginReturnedStronglyTypedDS(state.Author, cb, state)
Else
' Cannot throw the exception in this function or the XML Web
' service will hang. So, set the state argument to the
' exception and let the End method of the chained XML Web
' service check for it.
Dim ex As ArgumentException = New ArgumentException( _
"Author does not exist.", "Author")
Dim cb As AsyncCallback = state.originalCallback
' Call the second XML Web service, setting the state to an
' exception.
rs.BeginReturnedStronglyTypedDS(state.Author, cb, ex)
End If
End Sub
' Define the End method.
<WebMethod()> _
Public Function EndGetAuthorRoyalties(ByVal asyncResult As _
IAsyncResult) As localhost.AuthorRoyalties
' Return the asynchronous result from the other XML Web service.
Return remoteService.EndReturnedStronglyTypedDS(asyncResult)
End Function
End Class
' Class to wrap the callback and state for the intermediate asynchronous
' operation.
Public Class AsyncStateChain
Public originalCallback As AsyncCallback
Public originalState As Object
Public Author As String
End Class
End Namespace
請參閱
與 XML Web Service 進行非同步通訊 | 包含非同步呼叫 | 使用 ASP.NET 建置 XML Web Service