fundo
Estou desenvolvendo uma camada de serviço de API para um cliente e fui solicitado a capturar e registrar todos os erros globalmente.
Portanto, enquanto algo como um terminal (ou ação) desconhecido é facilmente manipulado usando o ELMAH ou adicionando algo como isto ao Global.asax
:
protected void Application_Error()
{
Exception unhandledException = Server.GetLastError();
//do more stuff
}
. . Os erros não manipulados que não estão relacionados ao roteamento não são registrados. Por exemplo:
public class ReportController : ApiController
{
public int test()
{
var foo = Convert.ToInt32("a");//Will throw error but isn't logged!!
return foo;
}
}
Eu também tentei definir o [HandleError]
atributo globalmente registrando este filtro:
filters.Add(new HandleErrorAttribute());
Mas isso também não registra todos os erros.
Problema / Pergunta
Como intercepto erros como o gerado pela chamada /test
acima para que eu possa registrá-los? Parece que essa resposta deve ser óbvia, mas eu tentei tudo o que consigo pensar até agora.
Idealmente, quero adicionar algumas coisas ao log de erros, como o endereço IP do usuário solicitante, data, hora e assim por diante. Também quero poder enviar um e-mail para a equipe de suporte automaticamente quando um erro for encontrado. Tudo isso eu posso fazer se eu puder interceptar esses erros quando eles acontecerem!
RESOLVIDO!
Graças a Darin Dimitrov, cuja resposta eu aceitei, resolvi isso. O WebAPI não trata erros da mesma maneira que um controlador MVC comum.
Aqui está o que funcionou:
1) Adicione um filtro personalizado ao seu espaço para nome:
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) Agora registre o filtro globalmente na classe 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());
}
}
OU você pode pular o registro e apenas decorar um único controlador com o [ExceptionHandling]
atributo
fonte
Respostas:
Se sua API da web estiver hospedada em um aplicativo ASP.NET, oApplication_Error
evento será chamado para todas as exceções não tratadas em seu código, incluindo a ação de teste que você mostrou. Portanto, tudo o que você precisa fazer é lidar com essa exceção dentro do evento Application_Error. No código de exemplo que você mostrou, você está manipulando apenas a exceção do tipoHttpException
que obviamente não é o caso doConvert.ToInt32("a")
código. Portanto, certifique-se de registrar e manipular todas as exceções nele:O tratamento de exceções na API da Web pode ser feito em vários níveis. Aqui está uma
detailed article
explicação das diferentes possibilidades:atributo de filtro de exceção personalizado que pode ser registrado como um filtro de exceção global
invocador de ação personalizada
fonte
Application_Error
evento, isso significa que algum outro código está consumindo-a antes. Por exemplo, você pode ter alguns HandleErrorAttributes, módulos personalizados, ... Existem muitos outros lugares onde as exceções podem ser capturadas e manipuladas. Mas o melhor lugar para fazer isso é o evento Application_Error, porque é onde todas as exceções não tratadas terminam./test
exemplo não é atingido. Coloquei um ponto de interrupção na primeira linha (Exception unhandledException = . . .
), mas não consigo atingi-lo no/test
cenário. Se eu inserir um URL falso, o ponto de interrupção será atingido.Application_Error
evento não é o local correto para lidar com exceções para a API da Web, porque não será acionado em todos os casos. Eu encontrei um artigo muito detalhado explicando as várias possibilidades de conseguir isso: weblogs.asp.net/fredriknormen/archive/2012/06/11/...Como complemento às respostas anteriores.
Ontem, o ASP.NET Web API 2.1 foi lançado oficialmente .
Oferece outra oportunidade para lidar com exceções globalmente.
Os detalhes são dados na amostra .
Resumidamente, você adiciona registradores de exceções globais e / ou manipulador de exceções globais (apenas um).
Você os adiciona à configuração:
E sua realização:
fonte
Por que relançar etc? Isso funciona e fará com que o serviço retorne o status 500 etc
fonte
você já pensou em fazer algo como um filtro de ação de erro de manipulação como
você também pode criar uma versão personalizada
[HandleError]
com a qual pode gravar informações de erro e todos os outros detalhes para registrarfonte
Embrulhe a coisa toda em uma tentativa / captura e registre a exceção não tratada e depois a repasse. A menos que haja uma maneira integrada melhor de fazer isso.
Aqui está uma referência Capturar todas (manipuladas ou não) Exceções
(editar: oh API)
fonte