Condividi tramite


Procedura: creare un gestore HTTP asincrono

Aggiornamento: novembre 2007

In questa procedura dettagliata viene illustrato come creare un gestore HTTP asincrono. I gestori HTTP asincroni consentono di avviare un processo esterno, ad esempio la chiamata a un metodo in un server remoto, senza interrompere l'elaborazione. Il gestore può infatti proseguire con l'elaborazione senza attendere la fine del processo esterno.

Durante l'elaborazione di un gestore HTTP asincrono, ASP.NET inserisce il thread che verrebbe normalmente utilizzato per il processo esterno nel pool di thread finché il gestore non riceve un callback dal processo esterno. In questo modo si evita il blocco dei thread e si migliorano le prestazioni, in quanto è possibile eseguire contemporaneamente solo un numero limitato di thread. Se molti utenti richiedono gestori HTTP sincroni basati su processi esterni, è possibile che il sistema operativo esaurisca rapidamente i thread consentiti perché molti di essi rimangono bloccati in attesa di un processo esterno.

Nell'esempio riportato in questa procedura dettagliata viene illustrato un gestore HTTP asincrono che elabora le richieste per i file con estensione SampleAsync in un'applicazione ASP.NET. Nell'esempio viene illustrato il codice per il gestore, quindi viene spiegato come eseguire il mapping dell'estensione SampleAsync al gestore in ASP.NET. Nell'esempio viene illustrato anche come eseguire il mapping dell'estensione SampleAsync ad ASP.NET in IIS, in modo tale che IIS inoltri ad ASP.NET le richieste terminanti con .SampleAsync.

Per ulteriori informazioni sull'interazione tra il runtime ASP.NET e IIS 6.0, vedere Cenni preliminari sul ciclo di vita delle applicazioni ASP.NET per IIS 5.0 e 6.0. Per ulteriori informazioni sull'integrazione di ASP.NET con IIS 7.0, vedere Cenni preliminari sul ciclo di vita delle applicazioni ASP.NET per IIS 7.0.

Di seguito sono elencate alcune delle attività illustrate nella procedura dettagliata:

  • Creazione di codice per una classe del gestore HTTP. che implementa il metodo ProcessRequest e la proprietà IsReusable.

  • Registrazione del gestore nel file Web.config e mapping dell'estensione di file SampleAsync a tale gestore.

  • Mapping dell'estensione di file SAMPLE ad ASP.NET in IIS.

Prerequisiti

Per completare questa procedura dettagliata è necessario disporre dei seguenti elementi:

  • Visual Studio o Visual Web Developer.

  • Un sito Web ASP.NET eseguibile mediante IIS.

  • IIS 6.0 o IIS 7.0.

Creazione di una classe del gestore HTTP asincrono

Per iniziare verrà creata una classe che implementa il gestore asincrono.

Per creare la classe di gestori HTTP HelloWorldAsyncHandler

  1. Se il sito Web utilizzato non possiede ancora una cartella App_Code, crearne una nella radice del sito.

  2. Nella directory App_Code, creare una classe denominata HelloWorldAsyncHandler e aggiungere il codice seguente al file della classe:

    Imports Microsoft.VisualBasic
    Imports System.Web
    Imports System.Threading
    
    Public Class HelloWorldAsyncHandler
        Implements IHttpAsyncHandler
    
        Public ReadOnly Property IsReusable() As Boolean Implements System.Web.IHttpHandler.IsReusable
            Get
                Return False
            End Get
        End Property
    
        Public Function BeginProcessRequest( _
            ByVal context As System.Web.HttpContext, _
            ByVal cb As System.AsyncCallback, _
            ByVal extraData As Object) _
            As System.IAsyncResult _
            Implements System.Web.IHttpAsyncHandler.BeginProcessRequest
            context.Response.Write("<p>Begin IsThreadPoolThread is " _
                & Thread.CurrentThread.IsThreadPoolThread & "</p>" & vbCrLf)
            Dim asynch As New AsynchOperation(cb, context, extraData)
            asynch.StartAsyncWork()
            Return asynch
        End Function
    
        Public Sub EndProcessRequest(ByVal result As _
             System.IAsyncResult) _
             Implements System.Web.IHttpAsyncHandler.EndProcessRequest
        End Sub
    
        Public Sub ProcessRequest(ByVal context _
                As System.Web.HttpContext) _
                Implements System.Web.IHttpHandler.ProcessRequest
            Throw New InvalidOperationException()
        End Sub
    End Class
    
    Class AsynchOperation
        Implements IAsyncResult
        Private _completed As Boolean
        Private _state As [Object]
        Private _callback As AsyncCallback
        Private _context As HttpContext
    
        ReadOnly Property IsCompleted() As Boolean _
                Implements IAsyncResult.IsCompleted
            Get
                Return _completed
            End Get
        End Property
    
        ReadOnly Property AsyncWaitHandle() As WaitHandle _
                Implements IAsyncResult.AsyncWaitHandle
            Get
                Return Nothing
            End Get
        End Property
    
        ReadOnly Property AsyncState() As [Object] _
                Implements IAsyncResult.AsyncState
            Get
                Return _state
            End Get
        End Property
    
        ReadOnly Property CompletedSynchronously() As Boolean _
                Implements IAsyncResult.CompletedSynchronously
            Get
                Return False
            End Get
        End Property
    
        Public Sub New(ByVal callback As AsyncCallback, _
                ByVal context As HttpContext, _
                ByVal state As [Object])
            _callback = callback
            _context = context
            _state = state
            _completed = False
        End Sub
    
        Public Sub StartAsyncWork()
            ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf StartAsyncTask), Nothing)
    
        End Sub
    
        Private Sub StartAsyncTask(ByVal workItemState As [Object])
            _context.Response.Write("<p>Completion IsThreadPoolThread is " & Thread.CurrentThread.IsThreadPoolThread & "</p>" & vbCrLf)
    
            _context.Response.Write("Hello World from Async Handler!")
            _completed = True
            _callback(Me)
    
        End Sub 'StartAsyncTask
    End Class 'AsynchOperation
    
    using System;
    using System.Web;
    using System.Threading;
    
    class HelloWorldAsyncHandler : IHttpAsyncHandler
    {
        public bool IsReusable { get { return false; } }
    
        public HelloWorldAsyncHandler()
        {
        }
        public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData)
        {
            context.Response.Write("<p>Begin IsThreadPoolThread is " + Thread.CurrentThread.IsThreadPoolThread + "</p>\r\n");
            AsynchOperation asynch = new AsynchOperation(cb, context, extraData);
            asynch.StartAsyncWork();
            return asynch;
        }
    
        public void EndProcessRequest(IAsyncResult result)
        {
        }
    
        public void ProcessRequest(HttpContext context)
        {
            throw new InvalidOperationException();
        }
    }
    
    class AsynchOperation : IAsyncResult
    {
        private bool _completed;
        private Object _state;
        private AsyncCallback _callback;
        private HttpContext _context;
    
        bool IAsyncResult.IsCompleted { get { return _completed; } }
        WaitHandle IAsyncResult.AsyncWaitHandle { get { return null; } }
        Object IAsyncResult.AsyncState { get { return _state; } }
        bool IAsyncResult.CompletedSynchronously { get { return false; } }
    
        public AsynchOperation(AsyncCallback callback, HttpContext context, Object state)
        {
            _callback = callback;
            _context = context;
            _state = state;
            _completed = false;
        }
    
        public void StartAsyncWork()
        {
            ThreadPool.QueueUserWorkItem(new WaitCallback(StartAsyncTask), null);
        }
    
        private void StartAsyncTask(Object workItemState)
        {
    
            _context.Response.Write("<p>Completion IsThreadPoolThread is " + Thread.CurrentThread.IsThreadPoolThread + "</p>\r\n");
    
            _context.Response.Write("Hello World from Async Handler!");
            _completed = true;
            _callback(this);
        }
    }
    

    Il codice implementa il metodo BeginProcessRequest. Il metodo scrive una stringa nella proprietà Response dell'oggettoHttpContext corrente, crea una nuova istanza della classe AsyncOperation e chiama il metodo StartAsyncWork. Il metodo StartAsyncWork quindi aggiunge il delegato StartAsyncTask all'oggetto ThreadPool. Quando un thread diventa disponibile viene chiamato il metodo StartAsyncTask, il quale scrive un'altra stringa nella proprietà Response. L'attività termina quindi richiamando il delegato AsyncCallback.

Registrazione del gestore HTTP personalizzato in IIS 6.0

Una volta creata la classe del gestore HTTP personalizzato, è necessario registrarla nel file Web.config dell'applicazione per consentire ad ASP.NET di individuare il gestore quando riceve richieste per risorse il cui URL termina con .SampleAsync.

Le procedure per la registrazione del gestore possono essere diverse, a seconda che si utilizzi IIS 6.0 o IIS 7.0. In questa sezione viene descritto come registrare un gestore in IIS 6.0. Nella sezione successiva verrà descritto come registrare un gestore in IIS 7.0.

Per registrare il gestore in IIS 6.0

  1. Se il sito Web non possiede ancora un file Web.config, crearne uno nella radice del sito.

  2. Aggiungere il markup evidenziato che segue al file Web.config:

    <configuration>
      <system.web>
        <httpHandlers>      <add verb="*" path="*.SampleAsync"         type="HelloWorldAsyncHandler"/>    </httpHandlers>
      </system.web>
    </configuration>
    

    L'elemento di configurazione registra il gestore HelloWorldAsyncHandler come gestore delle richieste che terminano con .SampleAsync.

  3. Registrare il mapping di un'estensione dell'applicazione per l'estensione di file SampleAsync utilizzando Gestione IIS. Per ulteriori informazioni, vedere Procedura: configurare un'estensione del gestore HTTP in IIS.

Registrazione del gestore HTTP personalizzato in IIS 7.0

In IIS 7.0 un'applicazione può essere eseguita in modalità classica o integrata. In modalità classica le richieste vengono elaborate in modo molto simile a quanto avviene in IIS 6.0. In modalità integrata, IIS 7.0 gestisce le richieste utilizzando una pipeline che consente di condividere richieste, moduli e altre funzionalità con ASP.NET.

Nel caso di IIS 7.0, il gestore viene registrato nel file Web.config o in Gestione IIS. Poiché in IIS 7.0 l'amministrazione è centralizzata, le modifiche apportate al file Web.config di un'applicazione si riflettono nell'interfaccia di Gestione IIS per l'applicazione e viceversa. Nelle procedure che seguono i gestori vengono registrati nel file Web.config.

Le procedure per la registrazione del gestore in IIS 7.0 sono diverse, a seconda che si utilizzi la modalità classica o la modalità integrata. Seguire la procedura relativa alla modalità IIS utilizzata.

Per registrare il gestore in IIS 7.0 eseguito in modalità classica

  1. Se il sito Web non possiede ancora un file Web.config, crearne uno nella radice del sito.

  2. Aggiungere l'elemento evidenziato di seguito al file Web.config:

    Nota:

    Sostituire il percorso corretto per il file aspnet_isapi.dll. Il file DLL si trova nella cartella in cui è installato .NET Framework. Per impostazione predefinita, la cartella è C:\WINDOWS\Microsoft.NET\Framework\versione.

    <configuration>
      <system.web>
        <httpHandlers>      <add verb="*" path="*.SampleAsync"         type="HelloWorldAsyncHandler"/>    </httpHandlers>
      </system.web>
      <system.webServer>
        <handlers>      <add  verb="*" path="*.SampleAsync"        name="HelloWorldAsyncHandler"        type="HelloWorldAsyncHandler"        modules="IsapiModule"/>        scriptProcessor="%path%\aspnet_isapi.dll"    </handlers>
      </system.webServer>
    </configuration>
    

    L'elemento di configurazione registra il gestore personalizzato in base al nome della classe ed esegue il mapping dell'estensione di file SampleAsync a tale gestore.

    Nota:

    Poiché si sta registrando un'estensione di file personalizzata, il gestore viene registrato sia nella sezione handlers sia nella sezione httpHandlers. In modalità classica, ai fini della compatibilità con le versioni precedenti, il gestore viene specificato come modulo ISAPI utilizzando l'attributo modules. Il percorso del file DLL ISAPI ASP.NET viene specificato mediante l'attributo scriptProcessor. L'attributo name è obbligatorio nella sezione handlers.

Per registrare il gestore in IIS 7.0 eseguito in modalità integrata

  1. Se il sito Web non possiede ancora un file Web.config, crearne uno nella radice del sito.

  2. Aggiungere l'elemento evidenziato di seguito al file Web.config:

    <configuration>
      <system.webServer>
        <handlers>      <add verb="*" path="*.SampleAsync"        name="HelloWorldAsyncHandler"        type="HelloWorldAsyncHandler"/>    </handlers>
      </system.webServer>
    </configuration>
    

    L'elemento di configurazione registra il gestore personalizzato in base al nome della classe ed esegue il mapping dell'estensione di file SampleAsync a tale gestore.

    Nota:

    La registrazione viene effettuata nella sezione handlers, non nella sezione httpHandlers. L'attributo name è obbligatorio.

Verifica del gestore HTTP personalizzato

Una volta creato e registrato il gestore HTTP personalizzato, è possibile verificarlo.

Per verificare il gestore HTTP personalizzato

  • Selezionare l'applicazione e immettere nel browser un URL che termina con .SampleAsync.

    Viene visualizzato il testo definito nella classe HelloWorldAsyncHandler.

Vedere anche

Attività

Procedura dettagliata: creazione di un gestore HTTP sincrono

Concetti

Cenni preliminari sul ciclo di vita delle applicazioni ASP.NET per IIS 5.0 e 6.0

Altre risorse

Introduzione ai gestori HTTP