Antecedentes
Estoy desarrollando una capa de servicio API para un cliente y se me ha pedido que capture y registre todos los errores a nivel mundial.
Entonces, mientras que algo como un punto final desconocido (o acción) se maneja fácilmente usando ELMAH o agregando algo como esto a Global.asax
:
protected void Application_Error()
{
Exception unhandledException = Server.GetLastError();
//do more stuff
}
. . Los errores no controlados que no están relacionados con el enrutamiento no se registran. Por ejemplo:
public class ReportController : ApiController
{
public int test()
{
var foo = Convert.ToInt32("a");//Will throw error but isn't logged!!
return foo;
}
}
También he intentado establecer el [HandleError]
atributo globalmente al registrar este filtro:
filters.Add(new HandleErrorAttribute());
Pero eso tampoco registra todos los errores.
Problema / Pregunta
¿Cómo intercepto errores como el generado al llamar /test
arriba para poder registrarlos? Parece que esta respuesta debería ser obvia, pero he intentado todo lo que puedo pensar hasta ahora.
Idealmente, quiero agregar algunas cosas al registro de errores, como la dirección IP del usuario solicitante, la fecha, la hora, etc. También quiero poder enviar un correo electrónico al personal de soporte automáticamente cuando se encuentre un error. ¡Todo esto lo puedo hacer si solo puedo interceptar estos errores cuando ocurren!
¡RESUELTO!
Gracias a Darin Dimitrov, cuya respuesta acepté, me di cuenta de esto. WebAPI no maneja los errores de la misma manera que un controlador MVC normal.
Esto es lo que funcionó:
1) Agregue un filtro personalizado a su espacio de nombres:
public class ExceptionHandlingAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
if (context.Exception is BusinessException)
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.InternalServerError)
{
Content = new StringContent(context.Exception.Message),
ReasonPhrase = "Exception"
});
}
//Log Critical errors
Debug.WriteLine(context.Exception);
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.InternalServerError)
{
Content = new StringContent("An error occurred, please try again or contact the administrator."),
ReasonPhrase = "Critical Exception"
});
}
}
2) Ahora registre el filtro globalmente en la clase WebApiConfig :
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{action}/{id}", new { id = RouteParameter.Optional });
config.Filters.Add(new ExceptionHandlingAttribute());
}
}
O puede omitir el registro y simplemente decorar un solo controlador con el [ExceptionHandling]
atributo.
fuente
Respuestas:
Si su API web está alojada dentro de una aplicación ASP.NET,Application_Error
se llamará al evento para todas las excepciones no controladas en su código, incluida la de la acción de prueba que ha mostrado. Entonces, todo lo que tiene que hacer es manejar esta excepción dentro del evento Application_Error. En el código de muestra que ha mostrado, solo está manejando una excepción de tipo,HttpException
que obviamente no es el caso con elConvert.ToInt32("a")
código. Así que asegúrese de iniciar sesión y manejar todas las excepciones allí:El manejo de excepciones en la API web podría hacerse en varios niveles. Aquí hay una
detailed article
explicación de las diferentes posibilidades:atributo de filtro de excepción personalizado que podría registrarse como un filtro de excepción global
invocador de acción personalizada
fuente
Application_Error
evento, esto significa que algún otro código la está consumiendo antes. Por ejemplo, puede tener algunos atributos HandleErrorAttributes personalizados, módulos personalizados, ... Hay miles de millones de otros lugares donde se pueden detectar y manejar excepciones. Pero el mejor lugar para hacerlo es el evento Application_Error, porque ahí es donde terminarán todas las excepciones no controladas./test
ejemplo no se ve afectado. He puesto un punto de interrupción en la primera línea (Exception unhandledException = . . .
) pero no puedo alcanzar ese punto de interrupción en el/test
escenario. Sin embargo, si pongo una URL falsa, se alcanza el punto de interrupción.Application_Error
evento no es el lugar correcto para manejar excepciones para la API web porque no se activará en todos los casos. He encontrado un artículo muy detallado que explica las diversas posibilidades para lograrlo: weblogs.asp.net/fredriknormen/archive/2012/06/11/…Como una adición a las respuestas anteriores.
Ayer, se lanzó oficialmente ASP.NET Web API 2.1 .
Ofrece otra oportunidad para manejar excepciones a nivel mundial.
Los detalles se dan en la muestra .
Brevemente, agrega registradores de excepciones globales y / o manejador de excepciones globales (solo uno).
Los agrega a la configuración:
Y su realización:
fuente
¿Por qué volver a tirar, etc.? Esto funciona y hará que el servicio devuelva el estado 500, etc.
fuente
¿Has pensado en hacer algo como un filtro de acción de error de manejo como
También puede crear una versión personalizada
[HandleError]
con la que puede escribir información de error y todos los demás detalles para iniciar sesiónfuente
Envuelva todo en un try / catch y registre la excepción no controlada, luego páselo. A menos que haya una mejor forma integrada de hacerlo.
Aquí hay una referencia Catch All (manejado o no manejado) Excepciones
(editar: oh API)
fuente