Compartir a través de


Uso de módulos y controladores HTTP para crear componentes de ASP.NET conectables

 

Scott Mitchell, 4GuysFromRolla.com
Atif Aziz, Skybow AG

Septiembre de 2004

Resumen: en este artículo, Scott Mitchell y Atif Aziz muestran cómo puede usar módulos y controladores HTTP para agregar el registro de errores a las aplicaciones de ASP.NET. (22 páginas impresas)

Descargue el archivo de ejemplo de MSDNElmah.msi.

Contenido

Introducción
ELMAH: Módulos y controladores de registro de errores
Una breve introducción a los controladores y módulos HTTP
Examen de la arquitectura de ELMAH
Adición de ELMAH a una aplicación web de ASP.NET
Conclusión
Referencias
Libros relacionados

Introducción

¿Alguna vez ha trabajado en una aplicación ASP.NET y ha diseñado algunas funciones o conjuntos de características útiles que desea poder reutilizar fácilmente en otra aplicación de ASP.NET? ASP.NET ofrece diferentes herramientas para la componenteción de diferentes tipos de funcionalidad. Las dos herramientas más comunes para reutilizar en ASP.NET son:

  • Controles de usuario y controles de servidor compilados personalizados para elementos y funcionalidades de la interfaz de usuario.
  • Bibliotecas de clases de .NET para código de acceso a datos y lógica empresarial.

Dos ASP.NET reutilizar herramientas que no reciben mucha atención son módulos y controladores HTTP.

Si no está familiarizado con lo que son los controladores y módulos HTTP, no se preocupe. Hablaremos más adelante sobre ellos en este artículo. Por ahora, solo tiene que entender que los módulos HTTP son clases que se pueden configurar para ejecutarse en respuesta a eventos que se activan durante la solicitud de un recurso de ASP.NET. Un controlador HTTP es una clase responsable de representar un recurso determinado o de un tipo determinado de recurso. De hecho, cada vez que agrega una página web de ASP.NET al proyecto, básicamente está escribiendo un controlador HTTP. Esto se debe a que cuando la parte HTML de una página web de ASP.NET se compila dinámicamente en tiempo de ejecución, hereda directa o indirectamente de System.Web.UI.Page, lo que sucede como una implementación del controlador HTTP. Esto es cierto independientemente de si se toma la estrategia insertada o de código subyacente.

Como sabe, una aplicación de ASP.NET normalmente consta de un conjunto de páginas web, que se invocan cuando lo solicitan los exploradores de un usuario final. Como ASP.NET desarrolladores, la mayoría del código que se escribe es específico de una solicitud de una página web determinada, como el código de la clase de código subyacente de una página determinada para mostrar los resultados de la base de datos en función de alguna consulta de búsqueda. Sin embargo, hay veces que es necesario escribir código ortogonal en una sola página web, código que se aplica a todas las páginas de una aplicación. Por ejemplo, es posible que deseemos realizar un seguimiento del orden con el que cada usuario se mueve alrededor de nuestro sitio web. Para ello, tendríamos que hacer que cada página registre la hora de la solicitud e información que identifique al usuario.

Una manera de proporcionar esta funcionalidad de registro sería agregar código que registró los datos de alemán en una base de datos del controlador de eventos Page_Load para cada página web del sitio. Sin embargo, este enfoque no es fácil de mantener o reutilizar. Cada vez que agregamos una nueva página de ASP.NET en nuestro sitio, tendríamos que asegurarnos de que incluimos el código de registro adecuado. Si queríamos agregar una funcionalidad similar a otro sitio, tendríamos que pasar por cada página de ese sitio y agregar el código necesario. Idealmente, la funcionalidad de registro sería lógica y físicamente independiente de la funcionalidad de cada página individual y agregarla a otro sitio sería tan simple como quitar un ensamblado en el directorio /bin del sitio.

Esta reutilización y mantenimiento es bastante posible con módulos y controladores HTTP. En este artículo, examinaremos un conjunto de módulos y controladores HTTP diseñados para hacer que el registro de errores sea un ejercicio muy fácil de mantener y reutilizable. El objetivo de este artículo es demostrar cómo se pueden usar controladores y módulos HTTP como una forma muy alta de componentes, lo que permite desarrollar, empaquetar y implementar conjuntos completos de funcionalidades como una sola unidad e independiente de las aplicaciones web. Lograremos este objetivo en gran parte a través de un examen de una aplicación que se beneficia de la reutilización y la componenteización a través de controladores y módulos HTTP.

ELMAH: Módulos y controladores de registro de errores

El Error Logging Modules And Handlers (ELMAH), que examinaremos a lo largo de este artículo, fueron escritos por el coautor Atif Aziz (http://www.raboof.com/) y demuestran un medio fácil de agregar funcionalidades de registro de errores a una aplicación web de ASP.NET. ELMAH muestra cómo se pueden usar módulos y controladores HTTP para proporcionar un alto grado de componentes para el código que es ortogonal a la aplicación web (como el registro en todo la aplicación). ELMAH es una solución verdaderamente conectable, lo que significa que se puede agregar dinámicamente a una aplicación web de ASP.NET en ejecución sin necesidad de volver a compilar ni volver a implementar.

Independientemente de lo bien escrito y probado que pueda ser una aplicación web determinada, las cosas seguirán funcionando cada momento y luego. Es posible que no sea el código defectuoso, podría ser que el servidor de correo electrónico no responde o que algunos daños en los datos provocan un error criptográfico. Independientemente del motivo, cuando se produzca una excepción, especialmente en un sitio activo, es importante que los detalles de la excepción se registren para ayudar a diagnosticar el problema. ELMAH proporciona un mecanismo para el registro y la notificación de errores centralizados. Cada vez que se produce una excepción en una aplicación de ASP.NET que no se detecta, ELMAH recibe una notificación y controla la excepción como se indica en el archivo Web.config. Esto puede incluir registrar los detalles de la excepción en una base de datos, enviar un correo electrónico a un administrador o ambos.

ELMAH no está diseñado para responder correctamente a excepciones no controladas. Simplemente registra los detalles de las excepciones no controladas. Una vez que ELMAH se ha agregado a una aplicación web de ASP.NET, se registran todas las excepciones no controladas que se produzcan en esta aplicación. ELMAH no afecta a la experiencia del usuario final cuando se produce una excepción no controlada. Seguirán viendo la página "Error del servidor" o, si tiene errores personalizados configurados para controlar errores HTTP 500, se les redirigirá a una página con un mensaje más fácil de usar. Pero en segundo plano, ELMAH habrá detectado que se produjo una excepción no controlada y registró los detalles.

ELMAH detecta excepciones no controladas por medio del evento HttpApplication del objeto Error. El evento Error se genera cada vez que se propaga una excepción no detectada durante el procesamiento de solicitudes, sea desde una biblioteca de clases de .NET o una página web de ASP.NET. Tenga en cuenta que muchas aplicaciones de ASP.NET implementan incorrectamente páginas de error personalizadas y control mediante una llamada al método Server.ClearError(). Al borrar el error, se impedirá que el evento Error se active (así como que se notifique al cliente) y, por tanto, ELMAH nunca tendrá la oportunidad de registrar la excepción. Para ponerlo de otra manera, al usar ClearError() en una página de error personalizada, el usuario verá que se produjo un problema, pero no lo hará.

Nota Para obtener más información sobre cómo crear páginas de error personalizadas, lea el artículo de Eli Robillard Rich Custom Error Handling with ASP.NET.

Nota Cuando se produce una excepción no controlada en un servicio web de ASP.NET, el evento Error no se propaga hasta módulos HTTP y, por tanto, ELMAH. En su lugar, el entorno de ejecución de ASP.NET intercepta y se devuelve un error SOAP al cliente. Para tener un error registrado en un servicio web, tendría que crear un extensión SOAP que escuchaba errores de SOAP.

Además de registrar detalles de excepciones no controladas, ELMAH también incluye un conjunto de controladores HTTP para ver el registro de errores. Hay una interfaz web para el registro, que puede proporcionar una lista de todos los errores no controladas, así como detalles sobre un error determinado (véase las figuras 1 y 2).

Aa479332.elmah_fig01(en-us,MSDN.10).gif

Figura 1. Visualización del registro de errores

Aa479332.elmah_fig02(en-us,MSDN.10).gif

Figura 2. Visualización de un error

Este registro de errores también se puede representar como RSS, lo que permite a un administrador recibir notificaciones a través de su agregador RSS favorito cuando se ha producido un error (consulte la figura 3).

Aa479332.elmah_fig03(en-us,MSDN.10).gif

Figura 3. Fuente RSS de errores

Nota RSS, que significa Realmente Simple Syndication, es un estándar con formato XML que se usa habitualmente para sindicar noticias y otros tipos de contenido cambiante. Para obtener más información sobre RSS, incluido cómo distribuir contenido mediante RSS, así como cómo crear un lector RSS basado en Web, considere la posibilidad de leer Crear un agregador de noticias en línea con ASP.NET.

Por motivos de brevedad, este artículo solo se centra en un subconjunto de las características de ELMAH, centrándose en los componentes clave. El código completo está disponible para su descarga con este artículo y le animamos a estudiarlo exhaustivamente para obtener los detalles de la implementación. También hay una configuración del área de trabajo de GotDotNet para ELMAH en http://workspaces.gotdotnet.com/elmah con el fin de debatir, notificar problemas y mantenerse al día de los cambios.

Soluciones existentes para el registro de errores centralizado

Aunque ASP.NET no proporciona funcionalidades integradas de registro y visualización de errores, el grupo de patrones de de Microsoft & Practices ha creado un registrador de errores de código abierto, el bloque de aplicaciones de administración de excepciones (EMAB). EmAB se diseñó para trabajar con aplicaciones .NET basadas en escritorio y web, pero no puede ayudar a sentir que EMAB se diseñó principalmente para aplicaciones de escritorio con aplicaciones web como una idea posterior porque EMAB, de forma predeterminada, publica los detalles de excepción en el registro de eventos de Windows. Aunque el registro de eventos es un almacén de respaldo adecuado para obtener información de excepción concisa para una aplicación de escritorio, la mayoría de las aplicaciones web ,especialmente las que se hospedan en un servidor compartido en una empresa de hospedaje web, se desactiven del registro de eventos porque el uso del registro de eventos requiere permisos especiales para permitir que la aplicación ASP.NET escriba en el registro de eventos. Concedido, EMAB es lo suficientemente flexible como para crear un publicador personalizado que registra información en una base de datos, pero es un paso adicional con el que usted, el desarrollador, se encarga.

Nota ELMAH se incluye con un módulo de registro de base de datos para Microsoft SQL Server 2000, que analizaremos más adelante. Con ELMAH también puede crear registradores de excepciones personalizados, como un registrador que registra los detalles de la excepción en un archivo XML en el sistema de archivos del servidor web. De hecho, podría ampliar ELMAH para usar el bloque de aplicaciones de administración de excepciones, si ya tenía un publicador personalizado escrito para emAB que quería usar.

Cómo se usa EMAB para registrar información de excepciones influye fuertemente en la capacidad de mantenimiento y reutilización de la aplicación web. Por ejemplo, un enfoque naïve para registrar información de excepciones sería colocar un bloque de try ...catch alrededor de cada bloque de código en cada página web de ASP.NET, llamando a EMAB en la sección catch.

private void Page_Load(object sender, EventArgs e)
{
  try {
    // Code that might cause an exception
  }
  catch (Exception ex) {
    // record exception information by calling exception logger library
  }
}

Este enfoque es infalible, ya que se acopla estrechamente el registro de excepciones a cada página web y cada ASP.NET, lo que lo convierte en cualquier cosa que sea fácil de mantener o reutilizable. Un mejor enfoque sería usar el EMAB en el evento Application_Error en Global.asax. Este enfoque ofrece una arquitectura más acoplada, fácil de mantener y reutilizable, ya que el código de publicación de excepciones no toca ninguna página web de ASP.NET y se encuentra en una ubicación centralizada. La desventaja de este enfoque es que no se puede conectar. Para agregar esta funcionalidad de registro de errores a otra aplicación web de ASP.NET, tendría que modificar la Global.asaxde esa aplicación, por lo que era necesario volver a compilar y volver a implementar la aplicación.

El punto de este artículo no es introducir un reemplazo de EMAB. En su lugar, es resaltar la componenteización posible por parte de los controladores y módulos HTTP. ELMAH ilustra cómo se puede tomar una tarea común, como el registro de errores centralizado y la componente para facilitar el mantenimiento y permitir un alto grado de reutilización. El propósito de ELMAH es ofrecer instrucciones para la componentesización de la funcionalidad aplicable.

Una breve introducción a los controladores y módulos HTTP

Antes de pasar a examinar los detalles de la arquitectura y la implementación de ELMAH, dediquemos un momento a revisar los controladores y módulos HTTP. Cada vez que una solicitud llega a un servidor web de IIS, IIS examina la extensión de la solicitud para decidir cómo continuar. Para contenido estático como páginas HTML, archivos CSS, imágenes, archivos JavaScript, etc., IIS controla la propia solicitud. Para contenido dinámico como páginas ASP, páginas web ASP.NET y servicios web ASP.NET, IIS delega la solicitud a un extensión ISAPI especificada. Una extensión ISAPI es un fragmento de código no administrado que sabe cómo representar solicitudes de un tipo determinado. Por ejemplo, la extensión ISAPI de asp.dll es responsable de representar solicitudes de páginas web ASP clásicas; la extensión ISAPI de aspnet_isapi.dll se invoca cuando una solicitud entra en un recurso de ASP.NET.

Además de las extensiones de ISAPI, IIS también permite filtros ISAPI. Un filtro ISAPI es un fragmento de código no administrado que se puede ejecutar en respuesta a los eventos generados por IIS. Durante el ciclo de vida de una solicitud, IIS pasa por varios pasos que generan los eventos correspondientes. Por ejemplo, se genera un evento cuando la solicitud llega primero a IIS, cuando la solicitud está a punto de autenticarse, cuando el contenido representado está a punto de devolverse al cliente, etc. Los filtros ISAPI se usan normalmente para proporcionar funcionalidades como reescritura de direcciones URL, compresión, autenticación y autorización especializadas, registro especializado, etc.

Cuando una solicitud de un recurso de ASP.NET llega a IIS, se enruta al motor de ASP.NET, que representa el contenido del recurso solicitado. El motor de ASP.NET se comporta mucho como IIS en que genera varios eventos a medida que la solicitud pasa a través de la canalización HTTP de ASP.NET. Además, el motor de ASP.NET delega la representación del recurso solicitado en una clase determinada. Mientras que IIS usa extensiones y filtros ISAPI no administrados, ASP.NET usa clases administradas denominadas controladores y módulos HTTP.

Un controlador HTTP es una clase responsable de representar un tipo determinado de recurso. Por ejemplo, la clase de código subyacente de una página web de ASP.NET es un controlador HTTP, sabiendo cómo representar el marcado de la página web determinada. Ayuda a pensar en los controladores como representadores especializados que saben cómo crear el marcado para un tipo determinado de recurso.

Nota Para obtener una explicación más detallada sobre los controladores HTTP, junto con algunas aplicaciones prácticas de controladores, asegúrese de leer Servicio de contenido dinámico con controladores HTTP.

Un módulo HTTP es una clase que puede pulsar en los distintos eventos que se generan a medida que una solicitud pasa por fases de su ciclo de vida en el servidor. Uno de estos ASP.NET evento de aplicación es el evento Error, que se desencadena cuando se produce una excepción no controlada, que es el evento ELMAH interesado.

Nota Para obtener más información sobre los módulos HTTP, incluido un vistazo a cómo usar módulos HTTP para implementar la reescritura de direcciones URL, consulte reescritura de url en ASP.NET.

La figura 4 proporciona una representación gráfica de la canalización HTTP de ASP.NET. Tenga en cuenta que el proceso comienza con una solicitud que llega a IIS. Suponiendo que el recurso solicitado esté configurado para que lo controle la extensión ISAPI de ASP.NET, IIS envía la solicitud a la extensión ISAPI aspnet_isapi.dll no administrada. Esta extensión ISAPI pasa la solicitud al motor de ASP.NET administrado. Durante el ciclo de vida de la solicitud, se pueden ejecutar uno o varios módulos HTTP, en función de los módulos registrados y de los eventos a los que se han suscrito. Por último, el motor de ASP.NET determina el controlador HTTP responsable de representar el contenido, invocando al controlador y devolviendo el contenido generado a IIS, que lo devuelve al cliente solicitante.

Aa479332.elmah_fig04(en-us,MSDN.10).gif

Figura 4. Flujo de datos a través del registrador de errores

ELMAH proporciona un registro de errores centralizado a través de un módulo HTTP que tiene un controlador de eventos para el evento Error. Cuando se desencadena el evento, ELMAH registra los detalles de la excepción. ELMAH también usa controladores HTTP que son principalmente responsables de generar marcado HTML y RSS para mostrar información del registro de errores.

Para configurar una aplicación web existente para usar varios controladores o módulos, se copia el módulo o el ensamblado del controlador en el directorio /bin de la aplicación web y se agregan algunas líneas de configuración al archivo Web.config.

Para configurar los módulos HTTP para una aplicación web, incluya un <sección httpModules> al archivo Web.config que especifica el tipo del módulo que se va a agregar:

<httpModules>
   <add name="ModuleName" type="ModuleType" />
</httpModules>

El ModuleType es una cadena que escribe el tipo del módulo, que es el nombre de clase completo (Namespace.ClassName) seguido del nombre del ensamblado. El atributo type también puede incluir información de control de versiones y referencia cultural, junto con un token de clave pública necesario para ensamblados con nombre seguro. En el fragmento de código siguiente se muestra la configuración de <httpModules> real que deberá usar para incluir el módulo de registro de errores de ELMAH en la aplicación de ASP.NET:

<httpModules>
  <add name="ErrorLog" type="GotDotNet.Elmah.ErrorLogModule, 
    GotDotNet.Elmah, Version=1.0.5527.0, Culture=neutral, 
    PublicKeyToken=978d5e1bd64b33e5" />
</httpModules>

Un controlador HTTP se puede usar en una aplicación web agregando un <sección httpHandlers> al archivo Web.config. Dado que un controlador HTTP representa el contenido de un tipo determinado de recurso, además de un atributo type, el elemento <httpHandlers> contiene un atributo path, que indica qué rutas de acceso de archivo o extensiones se deben asignar a este controlador HTTP. También hay un atributo verb que permite limitar el uso del controlador a tipos específicos de solicitudes HTTP, como en una solicitud GET o POST. En el ejemplo siguiente se crearía un controlador HTTP que se invoca para todas las solicitudes a los archivos con una extensión .ashx.

<httpHandlers>
   <add verb="*" path="*.ashx" type="HandlerType" />
</ httpHandlers >

El atributo type para el controlador HTTP se expresa mediante las mismas opciones de sintaxis que con los módulos HTTP. Esta configuración del Web.config también se puede colocar en el archivo machine.config, lo que tiene el efecto de habilitar los controladores y módulos para todas las aplicaciones web en el servidor. En el fragmento de código siguiente se muestra el elemento <httpHandlers> en el archivo Web.config de la demostración incluida en la descarga de este artículo. Tenga en cuenta que indica que las solicitudes entrantes a /elmah/default.aspx deben representarse mediante la clase ErrorLogPageFactory.

<httpHandlers>
    <add 
        verb="POST,GET,HEAD" 
        path="elmah/default.aspx" 
        type="GotDotNet.Elmah.ErrorLogPageFactory, 
          GotDotNet.Elmah, Version=1.0.5527.0, Culture=neutral, 
          PublicKeyToken=978d5e1bd64b33e5" />
</httpHandlers>

Como puede ver, agregar módulos y controladores HTTP a una aplicación web de ASP.NET es muy sencillo, se puede hacer en cuestión de segundos y no requiere ninguna recompilación ni reimplementación de la aplicación de ASP.NET. Este es el motivo por el que los módulos y controladores HTTP son una excelente herramienta para su reutilización y ofrecen un medio para componentes de la aplicación en piezas acopladas de forma flexible y altamente fáciles de mantener.

Examen de la arquitectura de ELMAH

La arquitectura de ELMAH consta de tres subsistemas:

  • Un subsistema de registro de errores
  • Un subsistema de módulo HTTP
  • Un subsistema de controlador HTTP

El subsistema de registro de errores es responsable de dos tareas: registrar errores en el registro y recuperar información de error del registro. El subsistema del módulo HTTP es responsable de registrar un error cuando se produce una excepción no controlada en la aplicación ASP.NET. El subsistema del controlador HTTP proporciona un medio para que el registro de errores se represente en el marcado, que constituye una interfaz basada en Web en el registro de errores, así como una fuente RSS.

Como se muestra en la figura 5, los subsistemas de controlador y módulo HTTP usan el subsistema de registro de errores. El subsistema del módulo HTTP envía información de excepción al subsistema de registro de errores, mientras que el subsistema del controlador HTTP lee y representa la información de error.

Aa479332.elmah_fig05(en-us,MSDN.10).gif

Figura 5. Dónde encaja el sistema de registro de errores

Para comprender mejor la arquitectura de ELMAH, vamos a examinar cada uno de estos tres subsistemas con más detalle.

Subsistema de registro de errores

El subsistema de registro de errores es responsable de registrar errores en el registro, así como ofrecer funcionalidades para recuperar detalles sobre un error determinado o un subconjunto de los errores. Esta funcionalidad está disponible mediante una serie de clases:

  • ErrorLog: Esta clase abstracta proporciona los métodos contractuales para leer y escribir en el registro.
  • Error: Esta clase contiene propiedades que describen los detalles de un error determinado.
  • ErrorLogEntry: Esta clase representa una instancia de Error determinada para un ErrorLogdeterminado. Básicamente, el ErrorLogEntry agrupa una instancia de Error con la instancia de ErrorLog de la que se originó.

Echemos un vistazo a estas tres clases y cómo funcionan con los módulos HTTP y los subsistemas de controlador HTTP para proporcionar una utilidad completa y centralizada de registro de excepciones.

Examen de la clase ErrorLog

Dependiendo de una estrategia o configuración de proyecto determinada, es posible que desee emplear otro almacén de respaldo para el registro de errores. Por ejemplo, en un servidor de producción, es posible que desee registrar excepciones en Microsoft SQL Server, pero en un servidor de desarrollo podría estar satisfecho simplemente almacenando los errores en un conjunto de archivos XML o en una base de datos de Microsoft Access. Para ofrecer la capacidad de usar almacenes de respaldo diferentes, el subsistema de registro de errores proporciona una clase base abstracta, ErrorLog, que define los métodos base que todos los registradores de errores elMAH deben implementar. Estos métodos son:

  • Log(Error): Registra un error en el almacén de respaldo. La clase Error representa información sobre una excepción no controlada; Analizaremos esta Error clase con más detalle en breve. Al registrar la información de error, el método Log() también debe asignar un identificador único al error.
  • GetError(id): Devuelve información sobre un error determinado en el registro.
  • GetErrors(...): Devuelve un subconjunto de errores del registro. El subsistema del controlador HTTP usa este método para mostrar el registro de errores de forma paginada, en lugar de mostrar todos los errores de a la vez.

ELMAH se distribuye con dos implementaciones de ErrorLog:

  • SqlErrorLog: registra errores en una base de datos de Microsoft SQL Server 2000 mediante el proveedor de System.Data.SqlClient. El SqlErrorLog requiere SQL Server 2000 porque aprovecha algunas de sus características XML, pero se trata de un detalle de implementación que se puede cambiar.
  • MemoryErrorLog: Registra errores en la memoria de la aplicación (RAM). En otras palabras, se enlaza al appDomain de forma que cada aplicación recibe su propio registro privado. No es necesario decir que este registro no sobrevive a los reinicios o la duración de la aplicación, por lo que es especialmente bueno para pruebas y propósitos de solución de problemas temporales cuando se pueden producir errores en otras implementaciones.

Puede usar cualquiera de estos registradores de excepciones simplemente agregando un par de líneas de texto al archivo Web.config de la aplicación web de ASP.NET. Si necesita almacenar detalles de error en algún lugar que no sea SQL Server o memoria de la aplicación, puede crear su propio registrador personalizado. Para implementar un registrador de errores para ELMAH, cree una clase que extienda ErrorLog y proporcione la implementación de la Log(), GetError()y GetErrors() en el almacén deseado.

Tenga en cuenta que tanto el módulo HTTP como los subsistemas de controlador de ELMAH interactúan directamente con la clase de ErrorLog especificada, ya sea SqlErrorLog, MemoryErrorLogo su propia clase de registro personalizada. El módulo HTTP registra información de excepción mediante la creación de una instancia de Error y la pasa al método Log() del método ErrorLog. Los controladores HTTP leen detalles sobre uno o varios errores a través de los métodos GetError() y GetErrors() del ErrorLog, que devuelven una instancia de ErrorLogEntry específica o un conjunto de instancias de ErrorLogEntry.

Un vistazo a la clase de error

El método Log() de ErrorLog espera un parámetro de entrada de tipo Error. Se usa una clase Error personalizada en lugar de la clase Exception proporcionada en .NET Framework porque la clase Exception es más adecuada para comunicar información de excepciones en la pila de código y durante la vigencia de una aplicación. Sin embargo, Exception objetos no son ideales para almacenar en un registro de excepciones debido a problemas de almacenamiento, escritura y portabilidad. Sí, se podría usar la serialización binaria para almacenar una instancia de Exception, pero esto requeriría que el objeto Exception se deserializara en un equipo con el mismo conjunto de tipos y ensamblados disponibles. Se trata de una limitación inaceptable (especialmente desde el punto de vista de la administración y las operaciones), ya que un registro y su contenido deben ser portátiles y no solo se pueden ver en una máquina con un entorno de ejecución o una configuración concretos. Además, una instancia de Exception a menudo carece de información de periferia específica de una aplicación web, como los valores de la colección ServerVariables de la solicitud web actual, algo que puede ser valioso para el diagnóstico. Por lo tanto, en resumen, la clase Error actúa como suplente para todos los tipos de excepción, manteniendo información de una excepción generada en una aplicación web.

La lista completa de propiedades de Error se muestra en la tabla 1.

Propiedad Descripción
Excepción La instancia de Exception representada por este error. Se trata de una propiedad en tiempo de ejecución que nunca se conserva junto con una instancia de la clase .
ApplicationName Nombre de la aplicación en la que se produjo este error.
Nombre de host Nombre de la máquina host donde se produjo este error. Un buen valor predeterminado es Environment.MachineName.
Tipo Tipo, clase o categoría del error. Normalmente, este sería el nombre de tipo completo (sans the assembly qualification) de la excepción.
Fuente El origen del error, normalmente igual que la propiedad Message de un objeto Exception.
Mensaje Texto breve que describe el error, normalmente igual que la propiedad Message de un objeto Exception.
Detalle Texto detallado del error, como el seguimiento de pila completo.
Usuario El usuario inició sesión en la aplicación en el momento del error, como el devuelto por Thread.CurrentPrincipal.Identity.Name.
Hora Fecha y hora en que se produjo el error. Esto siempre está en la hora local.
StatusCode Código de estado que se devuelve en el encabezado de respuesta como resultado del error. Por ejemplo, esto es 404 para un FileNotFoundException. Desafortunadamente, este valor no siempre se puede determinar de forma confiable desde dentro de ASP.NET. En algunos casos, este valor de StatusCode se puede notificar como cero.
WebHostHtmlMessage Mensaje HTML predeterminado que el host web (ASP.NET) habría generado en ausencia de páginas de error personalizadas.
ServerVariables Una NameValueCollection de variables de servidor web, como las contenidas en HttpRequest.ServerVariables.
QueryString Un NameValueCollection de variables de cadena de consulta HTTP, como las contenidas en HttpRequest.QueryString.
Forma Un NameValueCollection de variables de formulario, como las contenidas en HttpRequest.Form.
Galletas Una NameValueCollection de cookies enviadas por el cliente, como las contenidas en HttpRequest.Cookies.

La propiedad WebHostHtmlMessage necesita una explicación. Si la aplicación web de ASP.NET encuentra una excepción no controlada y no tiene configurada la aplicación para usar páginas de error personalizadas, verá una pantalla similar a la que se muestra en la figura 6. Se trata de una pantalla que cada desarrollador de ASP.NET ha visto demasiadas veces.

Aa479332.elmah_fig06(en-us,MSDN.10).gif

Figura 6. Página De error estándar

Cuando se produce una excepción, se accede al marcado HTML real de la pantalla correspondiente y se guarda en la propiedad WebHostHtmlMessage de la clase Error. Cuando se visita la página que muestra información detallada sobre una excepción determinada, si la instancia de Error correspondiente tiene un valor en su propiedad WebHostHtmlMessage, el visitante se presenta un vínculo a una página que mostrará la pantalla de información de excepción real (como se muestra en la figura 6). Lo ordenado aquí es que no solo se registra la excepción, sino que también puede visitar la página de error original generada por ASP.NET al examinar el registro más adelante. Y todo esto mientras tiene errores personalizados habilitados.

La clase Error también tiene métodos para serializar y deserializar su estado hacia y desde un formato XML. Consulte FromXml y ToXml en el código adjunto para obtener más información.

La clase ErrorLogEntry: Asociar un error con un errorLog

La clase final del subsistema de registro de errores es la clase ErrorLogEntry, que asocia una instancia de Error a una instancia de ErrorLog. Cuando el subsistema del controlador HTTP llama al método GetError() para recuperar información sobre una excepción determinada, el método GetError() recupera la información del almacén de respaldo específico y rellena esta información en una instancia de ErrorLogEntry. La clase ErrorLogEntry contiene tres propiedades:

  • Id: El identificador único de los detalles de la excepción.
  • Registro: Referencia a la instancia de ErrorLog que representa el almacén de respaldo.
  • Error: Instancia rellenada de la clase Error con los detalles del error específico.

Aunque el método GetError() devuelve una única instancia de ErrorLogEntry, el GetErrors() devuelve una lista de instancias de ErrorLogEntry. GetErrors() está especialmente diseñado para permitir que los errores se paginan a través de registros n a la vez.

En la figura 7 se muestra una vista actualizada de la arquitectura de ELMAH, que muestra más detalles en el subsistema de registro de errores.

Aa479332.elmah_fig07(en-us,MSDN.10).gif

Figura 7. Arquitectura actualizada

Subsistema del módulo HTTP

ELMAH consta de dos módulos HTTP: ErrorLogModule y ErrorMailModule. ErrorLogModule es un módulo HTTP que crea un controlador de eventos para el evento Error de la aplicación. En caso de una excepción no controlada, el módulo HTTP obtiene el registrador de errores adecuado tal como se especifica en la configuración de la aplicación y llama al método Log() en él, pasando una instancia de Error rellenada con la información de la excepción y el HttpContext para la solicitud actual. El código fuente siguiente muestra el código alemán de la clase ErrorLogModule:

public class ErrorLogModule : IHttpModule
{
    public virtual void Init(HttpApplication application)
    {
        application.Error += new EventHandler(OnError);
    }

    protected virtual ErrorLog ErrorLog
    {
        get { return ErrorLog.Default; }
    }

    protected virtual void OnError(object sender, EventArgs args)
    {
        HttpApplication application = (HttpApplication) sender;
        LogException(application.Server.GetLastError(), 
          application.Context);
    }

    protected virtual void LogException(Exception e, 
      HttpContext context)
    {
        try
        {
            this.ErrorLog.Log(new Error(e, context));
        }
        catch (Exception localException)
        {
            Trace.WriteLine(localException);
        }
    }
}

La ejecución del ErrorLogModulecomienza en el método Init(), donde indica al tiempo de ejecución de ASP.NET que se debe invocar el método OnError() siempre que se genere el evento Error. El método OnError() hace referencia al objeto HttpApplication y llama al método LogException(), pasando los detalles de la última excepción, así como la instancia de HttpContext específica de la solicitud concreta. LogException() simplemente llama al método Log() de la clase ErrorLog adecuado, pasando una nueva instancia de Error. (El constructor de la instancia de Error toma una instancia de Exception y HttpContext, y rellena las propiedades en consecuencia; consulte el código fuente disponible en la descarga para obtener más información).

El ErrorLogModule contiene una propiedad de ErrorLog de solo lectura y devuelve la instancia de ErrorLog devuelta por ErrorLog.Default. Default es una propiedad estática de tipo ErrorLog en la clase ErrorLog. Consulta la configuración de la aplicación web para determinar qué clase se va a usar para el registro de excepciones: SqlErrorLog, MemoryErrorLogo una clase de registro de excepciones personalizada.

Nota En la sección Agregar ELMAH a una aplicación web de ASP.NET examinaremos cómo configurar una aplicación web para usar un registrador de excepciones específico. Es tan sencillo como agregar un par de líneas a los archivos Web.config o machine.config.

El otro módulo HTTP del subsistema del módulo HTTP es la clase ErrorMailModule, que envía un correo electrónico a un administrador en caso de una excepción. No analizaremos esta parte de ELMAH, aunque puede examinar cómo usar este módulo en los ejemplos de código disponibles en la descarga de este artículo.

Subsistema del controlador HTTP

Recuerde que el propósito de los controladores HTTP es representar el contenido de un tipo determinado de recurso. Cuando una solicitud entra en la canalización HTTP de ASP.NET, el motor de ASP.NET examina la ruta de acceso solicitada y determina qué controlador HTTP se debe usar para controlar el recurso solicitado. En concreto, una aplicación de ASP.NET se puede configurar para tener una ruta de acceso determinada controlada por un controlador HTTP o un controlador HTTP fábrica. Un generador de controladores HTTP es una clase que no es responsable directa de representar el contenido, sino que es responsable de seleccionar y devolver una instancia del controlador HTTP. Esta instancia de controlador HTTP devuelta es la que se encarga de representar el recurso solicitado.

El subsistema de controlador HTTP de ELMAH consta de una serie de clases de controlador HTTP diseñadas para generar marcado para mostrar los errores registrados, junto con una única clase de generador de controladores HTTP. La clase de generador de controladores HTTP, ErrorLogPageFactory, examina la parte PathInfo de la dirección URL solicitada para determinar qué controlador HTTP debe generar la salida.

Nota La parte PathInfo de una dirección URL es cualquier contenido adicional que siga el nombre de archivo y está disponible a través de la propiedad PathInfo del objeto Request. Por ejemplo, en la dirección URL http://www.example.com/someDir/somePage.aspx/somePath, somePath es la parte PathInfo de la dirección URL. Para obtener más información sobre la terminología usada para las distintas partes de una dirección URL y las propiedades de objeto de Request correspondientes, consulte entrada de blog de Rick StrahlMaking Sense of ASP.NET Paths.

El siguiente fragmento de código muestra el código más interesante de la clase de generador de controladores HTTP ErrorLogPageFactory.

public class ErrorLogPageFactory : IHttpHandlerFactory
{
    public virtual IHttpHandler GetHandler(HttpContext context, 
      string requestType, string url, string pathTranslated)
    {
        string resource = 
          context.Request.PathInfo.Length == 0 ? string.Empty :
            context.Request.PathInfo.Substring(1);

        switch (resource.ToLower(CultureInfo.InvariantCulture))
        {
            case "detail" :
                return new ErrorDetailPage();

            case "html" :
                return new ErrorHtmlPage();

            case "rss" :
                return new ErrorRssHandler();

            default :
                return new ErrorLogPage();
        }
    }
}

Como puede ver, el método GetHandler() de la clase ErrorLogPageFactory devuelve una instancia de controlador HTTP basada en el PathInfo de la solicitud. Si el PathInfo es rss, se devuelve una instancia del controlador HTTP de ErrorRssHandler, que representa el registro como una fuente RSS. Si el PathInfo es detail, se devuelve una instancia de controlador HTTP ErrorDetailPage, que muestra información sobre una excepción determinada.

En la configuración de ASP.NET aplicación web, debe especificar una ruta de acceso que se asigne al generador de controladores HTTP de ErrorLogPageFactory, como ErrorLog.aspx. Para ver una fuente RSS del registro de excepciones, puede visitar: http://www.example.com/ErrorLog.aspx/rss.

Las distintas clases de controlador HTTP de ELMAH(ErrorDetailPage, ErrorHtmlPage, ErrorRssHandler, ErrorLogPage, etc.) representan un marcado diferente. El ErrorRssHandler controlador HTTP, por ejemplo, recorre en bucle los 15 errores más recientes y emite el marcado XML adecuado para mostrar esta información en un formato RSS. Todos los demás controladores HTTP se derivan, directa o indirectamente, de la clase System.Web.UI.Page (que es la clase de la que se derivan todas las clases de código subyacente ASP.NET). Estos controladores HTTP relacionados con la página invalidan los métodos Render() de la clase Page y OnLoad() para crear una interfaz HTML que muestra una lista paginable de las excepciones registradas. Consulte las figuras 1, 2 y 3 para ver las capturas de pantalla de estas páginas.

Note While the Error class saves the ServerVariables, QueryString, Form, and Cookie collections, only the ServerVariables collection is displayed in the details for an exception. Esto se debe a que los parámetros y las cookies de QueryString se pueden ver a través de los parámetros QUERY_STRING y HTTP_COOKIE del ServerVariable, respectivamente. La colección Form se omite porque esto podría incluir potencialmente decenas de kilobytes de información de estado de vista que normalmente sirve poco para la mayoría del diagnóstico. Por supuesto, puede modificar fácilmente los detalles del controlador HTTP para incluir esta información, si así lo elige.

Ahora que hemos examinado los tres subsistemas de ELMAH, echemos un vistazo a cómo agregar ELMAH a una aplicación web de ASP.NET existente. Preste especial atención a lo fácil que es agregar ELMAH a cualquier sitio, una ventaja de la componenteización que ofrecen los controladores HTTP y los módulos.

Adición de ELMAH a una aplicación web de ASP.NET

Agregar ELMAH a una aplicación web de ASP.NET es bastante sencillo y consta de dos pasos:

  • Agregar el ensamblado ELMAH a la aplicación web.
  • Configuración de la aplicación web para usar los módulos HTTP y los controladores HTTP de ELMAH.

ELMAH se puede aplicar a una aplicación web determinada en un servidor web copiando el ensamblado en el directorio /bin de la aplicación web y configurando la configuración de ELMAH a través del archivo Web.config. Además, puede configurar ELMAH para que se aplique a todas las aplicaciones web de en un servidor web agregando el ensamblado al de caché global de ensamblados (GAC) del servidor web y agregando las mismas opciones de configuración en machine.config en lugar de Web.config.

En el archivo Web.config (o machine.config), deberá agregar la siguiente configuración:

  • Un elemento <sectionGroup> en el elemento configSections <> que define un nuevo nombre de sección, <gotdotnet.elmah>, con una sección dentro de denominada <errorLog>, que tiene información sobre cómo registrar información de excepciones.
  • Una sección de <gotdotnet.elmah>, con una sección interna denominada <errorLog>, que contiene una referencia de tipo al registrador de excepciones que desea que use ELMAH, junto con cualquier configuración específica de ese registrador de excepciones.
  • Una entrada de la sección <httpHandlers> que indica la ruta de acceso que, cuando se visita a través de un explorador, representará varias vistas en el registro de errores.
  • Entrada de la sección <httpModules> que agrega el ErrorLogModule a la canalización HTTP de ASP.NET.

El siguiente fragmento de código del archivo Web.config incluido en la descarga de este artículo muestra cómo se pueden especificar estas cuatro opciones:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <!-- Allows for a new section group to the Web.config -->
    <sectionGroup name="gotdotnet.elmah">
      <!-- Indicates that inside the section group there will be an
              errorLog section -->
      <section name="errorLog" 
        type="System.Configuration.SingleTagSectionHandler, 
          System, Version=1.0.5000.0, Culture=neutral, 
          PublicKeyToken=b77a5c561934e089" />
    </sectionGroup>
  </configSections>

  <!-- This section group contains the type of the exception logger
         to use (SqlErrorLog, MemoryErrorLog, or a custom logger).
         It also contain properties pertinent to the exception logger
         (connectionString, for the SqlErrorLog). -->
  <gotdotnet.elmah>
    <errorLog type="GotDotNet.Elmah.SqlErrorLog, 
      GotDotNet.Elmah, Version=1.0.5527.0, Culture=neutral, 
      PublicKeyToken=978d5e1bd64b33e5" 
      connectionString="...connection string..." />
  </gotdotnet.elmah>

  <system.web>
    <!-- Register that a request to aspnetham/errorlog.aspx should
        be serviced by the ErrorLogPageFactory HTTP Handler factory -->
    <httpHandlers>
      <add verb="POST,GET,HEAD" path="elmah/default.aspx" 
        type="GotDotNet.Elmah.ErrorLogPageFactory, 
        Skybow.Samples.AspNetHam, Version=1.0.5527.0, 
        Culture=neutral, PublicKeyToken=978d5e1bd64b33e5" />
    </httpHandlers>

    <!-- Adds the ErrorLogModule HTTP Module to the HTTP pipeline. -->
    <httpModules>
      <add name="ErrorLog" type="GotDotNet.Elmah.ErrorLogModule, 
         GotDotNet.Elmah, Version=1.0.5527.0, Culture=neutral, 
         PublicKeyToken=978d5e1bd64b33e5" />
    </httpModules>
    
    ...
  </system.web>
</configuration>

El elemento <sectionGroup> del elemento <configSections> escribe que habrá un grupo de secciones adicional en el archivo de configuración denominado <gotdotnet.elmah>. Además, indica que dentro de esta sección personalizada habrá una sección <errorLog>. Dentro del elemento <gotdotnet.elmah> real hay un elemento <errorLog> que especifica qué implementación del registro de errores se debe usar. Recuerde que ELMAH se distribuye con dos implementaciones integradas, es decir, SqlErrorLog y MemoryErrorLog. Puede especificar cuál de estos dos usar o puede especificar para usar un registrador de excepciones personalizado que puede haber creado, en el elemento <errorLog>. El elemento <errorLog> también contiene la configuración específica de una implementación del registro de errores. Por ejemplo, al usar el elemento <errorLog> para indicar que se debe usar el SqlErrorLog, se debe incluir una propiedad connectionString que le indique cómo conectarse a la base de datos. El script SQL para crear la tabla adecuada y los procedimientos almacenados asociados se incluye en la descarga.

Nota Si desea que un administrador se envíe por correo electrónico en caso de una excepción no controlada, deberá agregar otro elemento de <section> en <sectionGroup> que defina un nuevo elemento denominado <errorMail>. Además, en el elemento <gotdotnet.elmah> real, tendría que agregar un elemento <errorMail>. Consulte el archivo Web.config en la descarga para obtener un ejemplo de esta sintaxis.

La sección <httpHandlers> especifica que el ErrorLogPageFactory (un generador de controladores HTTP) debe usarse para recuperar el controlador HTTP que representa el contenido para ver el registro de errores. El valor del atributo path indica la dirección URL relativa a la raíz virtual de la aplicación para obtenerla en la presentación del registro de errores. Puede cambiar esto a lo que quiera, pero asegúrese de que es una dirección URL con una extensión controlada por el motor de ASP.NET. Es decir, si cambia la ruta de acceso a algo parecido a errors.log, deberá configurar IIS para asignar solicitudes a errors.log a la extensión ISAPI de ASP.NET (aspnet_isapi.dll). Si desea asegurarse de que solo los administradores puedan ver el registro, use ASP. Las funcionalidades de autorización de direcciones URL de de NET restringir el acceso a un usuario específico o a un conjunto de usuarios o roles. Por otro lado, si desea deshabilitar completamente el acceso basado en Web al registro, simplemente no configure la sección <httpHandlers>.

La sección <httpModules> agrega el módulo HTTP de ErrorLogModule a la canalización HTTP de ASP.NET. Asegúrese de incluir esta configuración de <httpModules>; de lo contrario, ELMAH no escuchará el evento Error y, por lo tanto, no registrará ninguna excepción no controlada.

Como puede ver, agregar ELMAH a una aplicación web de ASP.NET existente es bastante sencillo. La implementación y reutilización simples de ELMAH se debe al hecho de que se ha componentedo mediante módulos y controladores HTTP.

Conclusión

Esperamos que este artículo haya podido aclarar cómo los controladores y módulos HTTP son herramientas excelentes para la funcionalidad de componentes ortogonal a una aplicación web de ASP.NET. Las tareas comunes, como el registro centralizado, el registro en toda la aplicación o las solicitudes de supervisión en toda la aplicación, se pueden agrupar mediante controladores y módulos. Al encapsular esta funcionalidad en un conjunto de componentes, obtiene ventajas de reutilización, mantenimiento e implementación sin necesidad de migración, integración ni recompilación de código y aplicaciones existentes.

Para demostrar la componenteización posible con módulos y controladores HTTP, examinamos ELMAH, un registro de errores centralizado y una aplicación de correo. ELMAH usa un módulo HTTP para escuchar cualquier evento de Error en toda la aplicación, que se desencadena como resultado de una propagación de excepciones no controladas. Al aprender de una excepción no controlada, ELMAH registra la excepción en una base de datos de SQL Server, en la memoria o, quizás, en algún otro almacén de respaldo. ELMAH también puede enviar por correo electrónico el contenido de la excepción a uno o varios destinatarios, como desarrolladores y personal de operaciones.

Además de un módulo HTTP, ELMAH contiene un conjunto de controladores HTTP y un generador de controladores HTTP para facilitar la visualización del registro de errores a través de un medio basado en Web. Esto incluye no solo una página web tradicional, sino también una fuente RSS. ELMAH mantiene un componente discreto al tener la funcionalidad de visualización ajustada en un controlador HTTP, en lugar de requerir que la aplicación web incluya una página web de ASP.NET que muestre dicha información. Mediante el uso de controladores HTTP, la implementación de ELMAH es un proceso sencillo y no requiere una recompilación de la aplicación web ni la carga de una página web de ASP.NET en el servidor de producción.

ELMAH es solo un ejemplo de la potencia de la componenteización que ofrecen los controladores HTTP y los módulos. Quizás haya otros procesos para toda la aplicación que haya implementado que se puedan beneficiar de la creación de componentes con controladores y módulos.

¡Feliz programación!

Agradecimientos

Antes de enviar este artículo al editor de MSDN, tuvimos una serie de voluntarios que ayudan a revisar el artículo y proporcionar comentarios sobre el contenido, la gramática y la dirección del artículo. Entre los colaboradores principales del proceso de revisión de este artículo se incluyen Milán Negovan, Carl Lambrecht, Bloster Kuster, Roman Mathis, Raffael Zaghet, Muhammad Abubakar y Patrick Schuler.

Referencias

Atif Aziz tiene casi 13 años de experiencia en desarrollo de soluciones en la plataforma Microsoft. Es consultor principal de Skybow AG, donde su principal enfoque es ayudar a los clientes a comprender y crear soluciones en la plataforma de desarrollo de .NET. Atif contribuye regularmente a la comunidad de desarrolladores de Microsoft al ofrecer charlas en conferencias de Microsoft y que no son de Microsoft y escribir artículos para publicaciones técnicas. Es orador de INETA y presidente del grupo de usuarios suizo de .NET (dotMUGS)más grande . Puede llegar a atif.aziz@skybow.com o a través de su sitio web en http://www.raboof.com.

Scott Mitchell, autor de cinco libros asp/ASP.NET y fundador de 4GuysFromRolla.com, ha estado trabajando con tecnologías web de Microsoft desde 1998. Scott trabaja como consultor independiente, entrenador y escritor. Puede acceder a él en mitchell@4guysfromrolla.com o a través de su blog, que se puede encontrar en http://ScottOnWriting.NET.

© Microsoft Corporation. Todos los derechos reservados.