共用方式為


建立非同步 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 非同步設計模式

  1. 將同步的 XML Web Service 方法分隔成兩種方法;每個都具有相同的基底名稱 - 一個從 Begin 開始而另一個從 End 開始。

  2. Begin 方法的參數清單包含所有的 in 和 by reference 參數,因為方法的功能結尾附加了這兩個參數。

    • By reference 參數列出為 in 參數。
    • 倒數第二個參數必須是 AsyncCallbackAsyncCallback 參數允許用戶端提供委派 (Delegate),在方法完成時叫用。當非同步 XML Web Service 方法呼叫另一個非同步方法時,這個參數可以傳遞到該方法的倒數第二個參數。
    • 最後一個參數是 ObjectObject 參數允許呼叫端對方法提供狀態資訊。當非同步 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
    
  3. 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