Cómo: Crear un controlador HTTP asincrónico
Actualización: noviembre 2007
Los controladores HTTP asincrónicos permiten iniciar un proceso externo, como por ejemplo una llamada a un método en un servidor remoto, mientras que el controlador continúa procesando sin esperar a que termine el proceso externo. Durante el procesamiento de un controlador HTTP asincrónico, ASP.NET coloca el subproceso que normalmente se utilizaría para el proceso externo de nuevo en el grupo de subprocesos hasta que el controlador reciba una devolución de llamada del proceso externo. Esto puede evitar el agrupamiento en bloques de los subprocesos y mejorar el rendimiento ya que solo es posible ejecutar inmediatamente un número limitado de subprocesos. Si varios usuarios solicitan controladores HTTP sincrónicos que dependan de procesos externos, el sistema operativo puede quedarse sin subprocesos rápidamente porque muchos estarán bloqueados y esperando un proceso externo.
El ejemplo de código siguiente muestra un controlador HTTP asincrónico que procesa solicitudes para los archivos con la extensión de nombre de archivo .SampleAsync dentro de una aplicación ASP.NET. El ejemplo muestra el código para el controlador y después cómo asignar la extensión .SampleAsync al controlador en ASP.NET. Finalmente, el ejemplo muestra cómo asignar la extensión .SampleAsync a ASP.NET en IIS, de modo que IIS reenvíe las solicitudes que terminen en .SampleAsync a ASP.NET.
Para obtener más información sobre cómo interactúa el motor en tiempo de ejecución de ASP.NET con IIS, vea Información general sobre el ciclo de vida de una aplicación ASP.NET para IIS 5.0 y 6.0.
Para crear la clase de controlador HTTP HelloWorldAsyncHandler
Cree una clase denominada HelloWorldAsyncHandler en su directorio App_Code y agregue el código siguiente al archivo de clase:
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); } }
El código implementa el método BeginProcessRequest. El método escribe una cadena en la propiedad Response del objeto actual HttpContext, crea una nueva instancia de la clase AsyncOperation y llama al método StartAsyncWork. El método StartAsyncWork agrega a continuación el delegado StartAsyncTask al objeto ThreadPool. Cuando un subproceso esté disponible, se llama al método StartAsyncTask, que escribe otra cadena en la propiedad Response y después la tarea finaliza al invocar al delegado AsyncCallback.
Registrar el controlador HTTP personalizado
Una vez creada la clase del controlador HTTP personalizado, se debe registrar en el archivo Web.config para que ASP.NET atienda las solicitudes de los archivos con la extensión .SampleAsync.
Para registrar el controlador HTTP personalizado en el archivo Web.config
Si su sitio Web aún no tiene un archivo Web.config, cree uno.
Agregue el código siguiente al archivo Web.config:
<configuration> <system.web> <httpHandlers> <add verb="*" path="*.SampleAsync" type="HelloWorldAsyncHandler"/> </httpHandlers> </system.web> </configuration>
El código registra el controlador HelloWorldAsyncHandler como el controlador para solicitudes que finalizan con .SampleAsync.
Configurar IIS para la extensión de controlador HTTP
IIS sólo pasa las solicitudes para ciertos tipos de archivo a ASP.NET para darles servicio. De forma predeterminada, los archivos con extensiones como .aspx, .ascx y .asmx ya están asignados a ASP.NET. Sin embargo, si desea que ASP.NET controle las extensiones de nombre de archivo definidas, debe registrarlas en IIS. Para obtener más información, vea Información general sobre el ciclo de vida de una aplicación ASP.NET para IIS 5.0 y 6.0.
Para asignar la extensión en IIS
Abra el Administrador de servicios de Internet.
Haga clic con el botón secundario del mouse (ratón) en la aplicación y elija Propiedades.
En la ficha Directorio, haga clic en Configuración.
Seleccione la ficha Asignaciones.
Agregue una nueva asociación que asigne .SampleAsync a la versión de Aspnet_isapi.dll que desea utilizar.
Si desea que el controlador se ejecute sin tener en cuenta la existencia o no de un archivo con el nombre que solicita el usuario, borre la casilla de verificación Comprobar si el archivo existe.
Probar el controlador HTTP personalizado
Una vez creado y registrado, puede probar el controlador HTTP personalizado solicitando un recurso con la extensión .SampleAsync de la aplicación.
Para probar el controlador HTTP personalizado
- Vaya a su aplicación y escriba una dirección URL en el explorador que finaliza en .SampleAsync.
Vea también
Tareas
Tutorial: Crear un controlador HTTP sincrónico
Conceptos
Información general sobre el ciclo de vida de una aplicación ASP.NET para IIS 5.0 y 6.0