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
Se il sito Web utilizzato non possiede ancora una cartella App_Code, crearne una nella radice del sito.
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
Se il sito Web non possiede ancora un file Web.config, crearne uno nella radice del sito.
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.
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
Se il sito Web non possiede ancora un file Web.config, crearne uno nella radice del sito.
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
Se il sito Web non possiede ancora un file Web.config, crearne uno nella radice del sito.
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