¿Cómo hacer que ELMAH trabaje con el atributo ASP.NET MVC ?

Estoy tratando de usar ELMAH para registrar errores en mi aplicación ASP.NET MVC, sin embargo, cuando uso el atributo [HandleError] en mis controladores, ELMAH no registra ningún error cuando se producen.

Como supongo, es porque ELMAH solo registra errores no controlados y el atributo [HandleError] está manejando el error, por lo que no es necesario iniciar sesión.

¿Cómo modifico o cómo voy a modificar el atributo para que ELMAH pueda saber que hubo un error y registrarlo?

Editar: Permítanme asegurarme de que todos entiendan, sé que puedo modificar el atributo, no es la pregunta que estoy formulando … ELMAH se saltea al usar el atributo handleerror, lo que significa que no verá que hubo un error porque se manejó ya por el atributo … Lo que estoy preguntando es si hay una manera de hacer que ELMAH vea el error y lo logre aunque el atributo lo maneje … Busqué alrededor y no veo ningún método al que llamar para forzarlo a que inicie sesión el error….

Puede subclase HandleErrorAttribute y anular su miembro OnException (no es necesario copiar) para que registre la excepción con ELMAH y solo si la implementación base se encarga de ello. La cantidad mínima de código que necesita es la siguiente:

 using System.Web.Mvc; using Elmah; public class HandleErrorAttribute : System.Web.Mvc.HandleErrorAttribute { public override void OnException(ExceptionContext context) { base.OnException(context); if (!context.ExceptionHandled) return; var httpContext = context.HttpContext.ApplicationInstance.Context; var signal = ErrorSignal.FromContext(httpContext); signal.Raise(context.Exception, httpContext); } } 

La implementación base se invoca primero, dándole la oportunidad de marcar la excepción como manejada. Solo entonces se señala la excepción. El código anterior es simple y puede causar problemas si se usa en un entorno donde el HttpContext puede no estar disponible, como las pruebas. Como resultado, querrá un código que sea más defensivo (a un costo ligeramente mayor):

 using System.Web; using System.Web.Mvc; using Elmah; public class HandleErrorAttribute : System.Web.Mvc.HandleErrorAttribute { public override void OnException(ExceptionContext context) { base.OnException(context); if (!context.ExceptionHandled // if unhandled, will be logged anyhow || TryRaiseErrorSignal(context) // prefer signaling, if possible || IsFiltered(context)) // filtered? return; LogException(context); } private static bool TryRaiseErrorSignal(ExceptionContext context) { var httpContext = GetHttpContextImpl(context.HttpContext); if (httpContext == null) return false; var signal = ErrorSignal.FromContext(httpContext); if (signal == null) return false; signal.Raise(context.Exception, httpContext); return true; } private static bool IsFiltered(ExceptionContext context) { var config = context.HttpContext.GetSection("elmah/errorFilter") as ErrorFilterConfiguration; if (config == null) return false; var testContext = new ErrorFilterModule.AssertionHelperContext( context.Exception, GetHttpContextImpl(context.HttpContext)); return config.Assertion.Test(testContext); } private static void LogException(ExceptionContext context) { var httpContext = GetHttpContextImpl(context.HttpContext); var error = new Error(context.Exception, httpContext); ErrorLog.GetDefault(httpContext).Log(error); } private static HttpContext GetHttpContextImpl(HttpContextBase context) { return context.ApplicationInstance.Context; } } 

Esta segunda versión intentará utilizar la señalización de error de ELMAH primero, que involucra la canalización completamente configurada como el registro, el envío de correos, el filtrado y lo que usted tiene. En su defecto, intenta ver si el error debe filtrarse. Si no, el error simplemente se registra. Esta implementación no maneja las notificaciones por correo. Si la excepción puede ser señalada, se enviará un correo electrónico si está configurado para hacerlo.

También puede tener que tener cuidado de que si hay varias instancias de HandleErrorAttribute en vigencia, entonces el registro duplicado no ocurre, pero los dos ejemplos anteriores deberían comenzar.

Lo siento, pero creo que la respuesta aceptada es excesiva. Todo lo que necesitas hacer es esto:

 public class ElmahHandledErrorLoggerFilter : IExceptionFilter { public void OnException (ExceptionContext context) { // Log only handled exceptions, because all other will be caught by ELMAH anyway. if (context.ExceptionHandled) ErrorSignal.FromCurrentContext().Raise(context.Exception); } } 

y luego registrarlo (el orden es importante) en Global.asax.cs:

 public static void RegisterGlobalFilters (GlobalFilterCollection filters) { filters.Add(new ElmahHandledErrorLoggerFilter()); filters.Add(new HandleErrorAttribute()); } 

Ahora hay un paquete ELMAH.MVC en NuGet que incluye una solución mejorada de Atif y también un controlador que maneja la interfaz elmah dentro del enrutamiento MVC (ya no es necesario usar ese eje).
El problema con esa solución (y con todas las que están aquí) es que de una forma u otra el manejador de errores de elma está manejando el error, ignorando lo que puede querer configurar como una etiqueta CustomError oa través de ErrorHandler o su propio manejador de errores
La mejor solución en mi humilde opinión es crear un filtro que actuará al final de todos los otros filtros y registrar los eventos que ya se han manejado. El módulo elmah debe encargarse de detectar los otros errores que la aplicación no maneja. Esto también le permitirá usar el monitor de estado y todos los demás módulos que se pueden agregar a asp.net para ver los eventos de error.

Escribí esto mirando con reflector en el ErrorHandler dentro de elmah.mvc

 public class ElmahMVCErrorFilter : IExceptionFilter { private static ErrorFilterConfiguration _config; public void OnException(ExceptionContext context) { if (context.ExceptionHandled) //The unhandled ones will be picked by the elmah module { var e = context.Exception; var context2 = context.HttpContext.ApplicationInstance.Context; //TODO: Add additional variables to context.HttpContext.Request.ServerVariables for both handled and unhandled exceptions if ((context2 == null) || (!_RaiseErrorSignal(e, context2) && !_IsFiltered(e, context2))) { _LogException(e, context2); } } } private static bool _IsFiltered(System.Exception e, System.Web.HttpContext context) { if (_config == null) { _config = (context.GetSection("elmah/errorFilter") as ErrorFilterConfiguration) ?? new ErrorFilterConfiguration(); } var context2 = new ErrorFilterModule.AssertionHelperContext((System.Exception)e, context); return _config.Assertion.Test(context2); } private static void _LogException(System.Exception e, System.Web.HttpContext context) { ErrorLog.GetDefault((System.Web.HttpContext)context).Log(new Elmah.Error((System.Exception)e, (System.Web.HttpContext)context)); } private static bool _RaiseErrorSignal(System.Exception e, System.Web.HttpContext context) { var signal = ErrorSignal.FromContext((System.Web.HttpContext)context); if (signal == null) { return false; } signal.Raise((System.Exception)e, (System.Web.HttpContext)context); return true; } } 

Ahora, en su configuración de filtro, quiere hacer algo como esto:

  public static void RegisterGlobalFilters(GlobalFilterCollection filters) { //These filters should go at the end of the pipeline, add all error handlers before filters.Add(new ElmahMVCErrorFilter()); } 

Tenga en cuenta que dejé un comentario allí para recordarle a las personas que si desean agregar un filtro global que realmente maneje la excepción debería ir ANTES de este último filtro, de lo contrario se encontrará con el caso en que el ElmahMVCErrorFilter ignorará la excepción no controlada. no se ha manejado y debe ser registrado por el módulo Elmah, pero luego el siguiente filtro marca la excepción tal como se manejó y el módulo lo ignora, lo que resulta en la excepción de que nunca lo convierte en elmah.

Ahora, asegúrate de que los appsets para elmah en tu webconfig se vean así:

           

El más importante aquí es “elmah.mvc.disableHandleErrorFilter”, si esto es falso usará el controlador dentro de elmah.mvc que realmente manejará la excepción usando el HandleErrorHandler predeterminado que ignorará la configuración de CustomErrorHandler

Esta configuración le permite establecer sus propias tags ErrorHandler en clases y vistas, mientras sigue registrando esos errores a través de ElmahMVCErrorFilter, agregando una configuración de error personalizada a su web.config a través del módulo elmah, incluso escribiendo sus propios manejadores de errores. Lo único que debe hacer es recordar no agregar ningún filtro que realmente maneje el error antes del filtro elmah que hemos escrito. Y olvidé mencionar: no hay duplicados en Elmah.

Puede tomar el código anterior e ir un paso más allá al introducir una fábrica de controladores personalizada que inyecta el atributo HandleErrorWithElmah en cada controlador.

Para obtener más información, consulte mi serie de blog sobre cómo iniciar sesión en MVC. El primer artículo cubre cómo configurar Elmah para MVC.

Hay un enlace al código descargable al final del artículo. Espero que ayude.

http://dotnetdarren.wordpress.com/

Soy nuevo en ASP.NET MVC. Me enfrenté al mismo problema, el siguiente es mi trabajo en mi Erorr.vbhtml (funciona si solo necesita registrar el error usando el registro de Elmah)

 @ModelType System.Web.Mvc.HandleErrorInfo @Code ViewData("Title") = "Error" Dim item As HandleErrorInfo = CType(Model, HandleErrorInfo) //To log error with Elmah Elmah.ErrorLog.GetDefault(HttpContext.Current).Log(New Elmah.Error(Model.Exception, HttpContext.Current)) End Code 

Sorry, an error occurred while processing your request.
@item.ActionName
@item.ControllerName
@item.Exception.Message

¡Es sencillo!

Una solución completamente alternativa es no usar MVC HandleErrorAttribute , y en su lugar confiar en el manejo de errores ASP.Net, que Elmah está diseñado para trabajar.

HandleErrorAttribute eliminar el HandleErrorAttribute global predeterminado de App_Start \ FilterConfig (o Global.asax), y luego configurar una página de error en su Web.config:

  

Tenga en cuenta que esto puede ser una URL enrutada MVC, por lo que lo anterior redirigiría a la acción ErrorController.Index cuando ocurra un error.

Para mí fue muy importante trabajar en el registro de correo electrónico. Después de un tiempo descubrí que esto solo necesita 2 líneas de código más en el ejemplo de Atif.

 public class HandleErrorWithElmahAttribute : HandleErrorAttribute { static ElmahMVCMailModule error_mail_log = new ElmahMVCMailModule(); public override void OnException(ExceptionContext context) { error_mail_log.Init(HttpContext.Current.ApplicationInstance); [...] } [...] } 

Espero que esto ayude a alguien 🙂

¡Esto es exactamente lo que necesitaba para la configuración de mi sitio MVC!

OnException una pequeña modificación al método OnException para manejar múltiples instancias de HandleErrorAttribute , como lo sugiere Atif Aziz:

tenga en cuenta que puede tener que tener cuidado de que si hay varias instancias de HandleErrorAttribute en vigencia, entonces el registro duplicado no se produce.

Simplemente compruebo context.ExceptionHandled antes de invocar la clase base, solo para saber si alguien más manejó la excepción antes del controlador actual.
Funciona para mí y publico el código en caso de que alguien más lo necesite y para preguntar si alguien sabe si pasé por alto algo.

Espero que sea útil:

 public override void OnException(ExceptionContext context) { bool exceptionHandledByPreviousHandler = context.ExceptionHandled; base.OnException(context); Exception e = context.Exception; if (exceptionHandledByPreviousHandler || !context.ExceptionHandled // if unhandled, will be logged anyhow || RaiseErrorSignal(e) // prefer signaling, if possible || IsFiltered(context)) // filtered? return; LogException(e); }