Creazione dei metodi asincroni di un servizio Web XML

Per migliorare le prestazioni, i metodi dei servizi Web XML che richiamano metodi dai lunghi tempi di esecuzione, che bloccano il thread, possono essere esposti come metodi asincroni. Quando si implementa un metodo di un servizio Web XML come asincrono, si consente al relativo thread, che viene restituito al pool di thread, di eseguire altro codice. In tal modo si disporrà di un thread in più, del limitato numero di thread del pool di thread, con il conseguente miglioramento generale delle prestazioni e della scalabilità del sistema.

L'implementazione asincrona è solitamente consigliata, ad esempio, per i metodi dei servizi Web XML che chiamano metodi che svolgono operazioni di I/O. Metodi di questo tipo sono, ad esempio, quelli attraverso cui avvengono la comunicazione con altri servizi Web XML, l'accesso a database remoti, l'I/O di rete e la lettura e scrittura di file di grandi dimensioni. La maggior parte del tempo di esecuzione di tali metodi è dedicata a elaborazioni hardware che comportano il blocco del thread che esegue il servizio Web XML. Per liberare tale thread e destinarlo all'esecuzione di altro codice è possibile implementare il metodo del servizio Web XML come asincrono.

Indipendentemente dal fatto che un metodo di un servizio Web XML sia o meno implementato come asincrono, la comunicazione con i client può essere asincrona. La comunicazione asincrona viene esposta ai client .NET all'interno della classe proxy generata dallo strumento del linguaggio di descrizione dei servizi Web (WSDL.EXE), anche se il metodo del servizio Web XML è implementato in modo sincrono. Nella classe proxy sono inclusi i metodi Begin e End per la comunicazione asincrona con tutti i metodi dei servizi Web XML. La decisione di implementare un metodo di un servizio Web XML come sincrono o asincrono va pertanto ricondotta esclusivamente a finalità inerenti le prestazioni.

Nota   La scelta di implementare un metodo di un servizio Web XML come asincrono non ha impatto sulla connessione HTTP tra il client e il server che ospita il servizio stesso. La connessione HTTP non viene chiusa né rimandata al pool.

Per implementare un metodo di un servizio Web XML in modo asincrono

L'implementazione asincrona di un metodo di un servizio Web XML segue il modello di progettazione asincrona di .NET Framework

  1. Dividere il metodo sincrono del servizio Web XML in due metodi i cui nomi abbiano la stessa radice e comincino uno con Begin e l'altro con End.

  2. Nell'elenco dei parametri del metodo Begin vi sono tutti i parametri in e by reference adibiti alle funzionalità del metodo più due ulteriori parametri finali.

    • I parametri by reference vengono elencati come parametri in.
    • Il penultimo parametro deve essere un AsyncCallback. Attraverso il parametro AsyncCallback, il client potrà indicare un delegato che verrà richiamato al termine dell'esecuzione del metodo. Quando un metodo asincrono di un servizio Web XML chiama un altro metodo asincrono, questo parametro potrà essere passato come penultimo parametro.
    • L'ultimo parametro è un Object. Attraverso il parametro Object, il chiamante può fornire informazioni sullo stato al metodo chiamato. Quando un metodo asincrono di un servizio Web XML chiama un altro metodo asincrono, questo parametro potrà essere passato come ultimo parametro.
    • Il valore restituito deve essere di tipo IAsyncResult.

    Nell'esempio di codice che segue viene mostrato un metodo Begin che accetta un parametro String ai fini delle proprie funzionalità.

    [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. L'elenco dei parametri del metodo End è costituito da un IAsyncResult seguito dai parametri out e by reference specifici delle funzionalità del metodo.

    • Il valore restituito è dello stesso tipo del valore restituito dal metodo sincrono.
    • I parametri by reference vengono elencati come parametri out.

    Nell'esempio di codice che segue viene mostrato un metodo End che restituisce un tipo definito dall'utente, AuthorRoyalties.

    [WebMethod]
    public AuthorRoyalties EndGetAuthorRoyalties(IAsyncResult
                                       asyncResult)
    [Visual Basic]
    <WebMethod()> _
    Public Function EndGetAuthorRoyalties(ByVal asyncResult As _
                        IAsyncResult) As AuthorRoyalties
    

    Nell'esempio di codice che segue viene mostrato un metodo asincrono di un servizio Web XML che comunica in modo asincrono con un altro metodo di un servizio Web XML.

    using System;
    using System.Web.Services;
    
    [WebService(Namespace="http://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:="http://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
    

Nell'esempio di codice che segue viene mostrato come porre in sequenza le diverse chiamate asincrone eventualmente effettuate da un metodo di un servizio Web XML. Il metodo BeginGetAuthorRoyalties effettua una chiamata asincrona per determinare se l'autore passato in ingresso è valido e imposta un callback intermedio denominato AuthorRoyaltiesCallback per ricevere i risultati. Se l'autore è valido, il callback intermedio effettuerà una chiamata asincrona per ricevere informazioni sui relativi diritti.

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="http://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:="http://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

Vedere anche

Comunicazione asincrona con servizi Web XML | Inserimento di chiamate asincrone | Generazione di servizi Web XML mediante ASP.NET