c# - Ni el filtro global de excepciones ni el error Application_Error están detectando excepciones no controladas
asp.net-mvc asp.net-mvc-4 (2)
Tengo un filtro de excepción global llamado LogErrorAttribute
:
public class LogErrorAttribute : IExceptionFilter
{
private ILogUtils logUtils;
public void OnException(ExceptionContext filterContext)
{
if (this.logUtils == null)
{
this.logUtils = StructureMapConfig.Container.GetInstance<ILogUtils>();
}
this.logUtils.LogError(HttpContext.Current.User.Identity.GetUserId(), "Unknown error.", filterContext.Exception);
}
}
Se registra junto con el filtro estándar HandleErrorAttribute
:
filters.Add(new LogErrorAttribute());
filters.Add(new HandleErrorAttribute());
Estoy registrando esos filtros como este:
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
También tengo un respaldo de Application_Error
:
protected void Application_Error()
{
var exception = Server.GetLastError();
Server.ClearError();
var httpException = exception as HttpException;
//Logging goes here
var routeData = new RouteData();
routeData.Values["controller"] = "Error";
routeData.Values["action"] = "Index";
if (httpException != null)
{
if (httpException.GetHttpCode() == 404)
{
routeData.Values["action"] = "NotFound";
}
Response.StatusCode = httpException.GetHttpCode();
}
else
{
Response.StatusCode = 500;
}
// Avoid IIS7 getting involved
Response.TrySkipIisCustomErrors = true;
// Execute the error controller
if (exception != null)
{
this.errorLogger.Log(LogLevel.Error, "An unknown exception has occurred.", exception);
}
else if (httpException != null)
{
this.errorLogger.Log(LogLevel.Error, "An unknown HTTP exception has occurred.", httpException);
}
else
{
this.errorLogger.Log(LogLevel.Error, "An unknown error has occurred.");
}
}
Ahora, tengo un controlador API que toma algunos datos de la base de datos y luego usa AutoMapper
para mapear los modelos para ver los modelos:
var viewModels = AutoMapper.Mapper.Map(users, new List<UserViewModel>());
Dentro de esa configuración de AutoMapper
, se ejecuta una resolución personalizada para una de las propiedades:
var appModuleAssignments = this.appModuleAssignmentManager.Get(userId);
var appModules = appModuleAssignments.Select(x => this.appModuleManager.Get(x.AppModuleId));
return AutoMapper.Mapper.Map(appModules, new List<AppModuleViewModel>());
En este momento estoy forzando a la instrucción appModuleManager.Get
a lanzar una excepción regular:
throw new Exception("Testing global filter.");
Posteriormente, esto AutoMapper
una excepción en AutoMapper
, ambos de los cuales no se manejan, sin embargo, ni el filtro global ni el AutoMapper
esta excepción.
¿Qué hice mal aquí?
Un par de cosas que he hecho desde la publicación:
- Se agregó el atributo
customErrors
alWeb.config
para activarlos. - Se
HandleErrorAttribute
el filtro globalHandleErrorAttribute
porque me di cuenta de que estaba configurando el error para que se manejara incluso si se estaba ejecutando. No esperaría que se ejecutara de todos modos porque este error ocurre fuera del controlador, pero probablemente me hubiera mordido más tarde.
La respuesta corta es que está agregando un Filtro de Excepciones MVC en lugar de un Filtro de Excepciones de API Web .
Su implementación verifica ExceptionContext
lugar de HttpActionExecutedContext
public override void OnException(HttpActionExecutedContext actionExecutedContext)
Dado que el marco generará una Excepción Http en lugar de una Excepción MVC , su método de anulación OnException
no se activa.
Entonces, un ejemplo más completo:
public class CustomExceptionFilter : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext actionExecutedContext)
{
message = "Web API Error";
status = HttpStatusCode.InternalServerError;
actionExecutedContext.Response = new HttpResponseMessage()
{
Content = new StringContent(message, System.Text.Encoding.UTF8, "text/plain"),
StatusCode = status
};
base.OnException(actionExecutedContext);
}
}
Otro paso importante es registrar su Filtro de Excepciones de la API Web Global en WebApiConfig.cs, en el método de Register(HttpConfiguration config)
.
public static void Register(HttpConfiguration config)
{
...
config.Filters.Add(new CustomExceptionFilter());
}
La respuesta de Dave Alperovich resolverá su problema usando HttpActionExecutedContext
public override void OnException(HttpActionExecutedContext context)
Sin embargo, mientras intenta capturar todas las excepciones posibles que su aplicación podría generar, entonces, aparte de los filtros de excepción, también debería usar los controladores de mensajes. Puede encontrar una explicación detallada aquí: http://www.asp.net/web-api/overview/error-handling/web-api-global-error-handling .
En resumen, hay una serie de casos que los filtros de excepción no pueden manejar. Por ejemplo:
- Excepciones lanzadas desde los constructores de controladores.
- Excepciones lanzadas desde los manejadores de mensajes.
- Excepciones lanzadas durante el enrutamiento.
- Excepciones lanzadas durante la serialización del contenido de la respuesta.
Por lo tanto, si se produce un error no manejado desde cualquier lugar dentro de la aplicación, su administrador de excepciones lo detectará y le permitirá tomar medidas específicas .
//Global exception handler that will be used to catch any error
public class MyExceptionHandler : ExceptionHandler
{
private class ErrorInformation
{
public string Message { get; set; }
public DateTime ErrorDate { get; set; }
}
public override void Handle(ExceptionHandlerContext context)
{
context.Result = new ResponseMessageResult(context.Request.CreateResponse(HttpStatusCode.InternalServerError,
new ErrorInformation { Message="An unexpected error occured. Please try again later.", ErrorDate=DateTime.UtcNow }));
}
}