Como obter o ELMAH para trabalhar com o atributo ASP.NET MVC ?

Eu estou tentando usar o ELMAH para registrar erros no meu aplicativo ASP.NET MVC, no entanto, quando eu uso o atributo [HandleError] em meus controladores, o ELMAH não registra nenhum erro quando eles ocorrem.

Como estou supondo, é porque o ELMAH registra somente erros não manipulados e o atributo [HandleError] está manipulando o erro, portanto, não é necessário registrá-lo.

Como eu modifico ou como eu altero o atributo para que o ELMAH saiba que houve um erro e registre-o ..

Edit: Deixe-me ter certeza de que todos entendam, eu sei que posso modificar o atributo que não é a pergunta que estou perguntando … ELMAH é ignorado ao usar o atributo handleerror, o que significa que ele não verá que houve um erro porque foi manipulado já pelo atributo … O que estou perguntando é que existe uma maneira de fazer o ELMAH ver o erro e logar mesmo que o atributo tenha manipulado ele … procurei por aí e não vejo nenhum método para chamar para forçá-lo a logar o erro….

Você pode subclassificar HandleErrorAttribute e replace seu membro OnException (não é necessário copiar) para que ele registre a exceção com ELMAH e somente se a implementação base manuseá-lo. A quantidade mínima de código que você precisa é a seguinte:

 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); } } 

A implementação base é chamada primeiro, dando a chance de marcar a exceção como sendo manipulada. Só então a exceção é sinalizada. O código acima é simples e pode causar problemas se usado em um ambiente no qual o HttpContext pode não estar disponível, como teste. Como resultado, você desejará um código mais defensivo (com o custo de ser um pouco mais longo):

 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 versão tentará usar a sinalização de erro do ELMAH primeiro, que envolve o pipeline totalmente configurado, como logging, mailing, filtragem e o que você tem. Falhando nisso, ele tenta ver se o erro deve ser filtrado. Se não, o erro é simplesmente registrado. Essa implementação não manipula notifications por email. Se a exceção puder ser sinalizada, um email será enviado se configurado para isso.

Você também pode ter que tomar cuidado para que, se várias instâncias HandleErrorAttribute estiverem em vigor, o log duplicado não ocorra, mas os dois exemplos acima devem ser iniciados.

Desculpe, mas acho que a resposta aceita é um exagero. Tudo o que você precisa fazer é isto:

 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); } } 

e registre-o (a ordem é importante) em Global.asax.cs:

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

Existe agora um pacote ELMAH.MVC no NuGet que inclui uma solução aprimorada da Atif e também um controlador que lida com a interface elmah no roteamento MVC (não é mais necessário usar esse axd)
O problema com essa solução (e com todos os aqui) é que, de uma forma ou de outra, o manipulador de erro elmah está realmente manipulando o erro, ignorando o que você pode querer configurar como uma tag customError ou através de ErrorHandler ou seu próprio manipulador de erro
A melhor solução IMHO é criar um filtro que irá atuar no final de todos os outros filtros e registrar os events que já foram manipulados. O módulo elmah deve cuidar do registro dos outros erros não manipulados pelo aplicativo. Isso também permitirá que você use o monitor de integridade e todos os outros módulos que podem ser adicionados ao asp.net para examinar events de erro

Eu escrevi isso olhando com reflector no ErrorHandler dentro 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; } } 

Agora, na configuração do seu filtro, você quer fazer algo assim:

  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()); } 

Observe que deixei um comentário lá para lembrar as pessoas de que, se quiserem adicionar um filtro global que realmente manipulará a exceção, ele deve passar ANTES que o último filtro, caso contrário, a exceção não tratada será ignorada pelo ElmahMVCErrorFilter porque ele não foi tratado e deve ser registrado pelo módulo Elmah, mas o próximo filtro marca a exceção como tratada e o módulo o ignora, resultando na exceção que nunca o transforma em elmah.

Agora, certifique-se de que as appsettings for elmah no seu webconfig sejam parecidas com esta:

           

O mais importante aqui é “elmah.mvc.disableHandleErrorFilter”, se isso for falso, ele usará o manipulador dentro de elmah.mvc que realmente manipulará a exceção usando o padrão HandleErrorHandler que irá ignorar suas configurações customError

Essa configuração permite que você defina suas próprias tags ErrorHandler em classs e exibições, enquanto ainda registra esses erros por meio do ElmahMVCErrorFilter, adicionando uma configuração customError ao seu web.config por meio do módulo elmah, até mesmo escrevendo seus próprios Error Handlers. A única coisa que você precisa fazer é lembrar de não adicionar nenhum filtro que realmente manipule o erro antes do filtro elmah que escrevemos. E eu esqueci de mencionar: não há duplicatas em elmah.

Você pode pegar o código acima e dar um passo adiante introduzindo uma fábrica de controladores personalizada que injeta o atributo HandleErrorWithElmah em cada controlador.

Para mais informações, confira minha série de blogs sobre como fazer login no MVC. O primeiro artigo aborda a instalação do Elmah e a execução do MVC.

Há um link para o código para download no final do artigo. Espero que ajude.

http://dotnetdarren.wordpress.com/

Eu sou novo no asp.net MVC. Eu enfrentei o mesmo problema, o seguinte é o meu viável no meu Erorr.vbhtml (funciona se você só precisa registrar o erro usando Elmah log)

 @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

É simplesmente!

Uma solução completamente alternativa é não usar o MVC HandleErrorAttribute e, em vez disso, confiar no tratamento de erros do ASP.Net, com o qual o Elmah foi projetado para trabalhar.

Você precisa remover o HandleErrorAttribute global padrão de App_Start \ FilterConfig (ou Global.asax) e, em seguida, configurar uma página de erro no seu Web.config:

  

Observe que isso pode ser uma URL roteada do MVC, portanto, o acima seria redirecionado para a ação ErrorController.Index quando ocorrer um erro.

Para mim, era muito importante que o log de e-mail estivesse funcionando. Depois de algum tempo eu descobri que isso precisa de apenas 2 linhas de código mais no exemplo 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 isso ajude alguém 🙂

Isso é exatamente o que eu precisava para a configuração do meu site MVC!

Eu adicionei uma pequena modificação ao método OnException para manipular várias instâncias HandleErrorAttribute , como sugerido por Atif Aziz:

Tenha em mente que você pode ter que tomar cuidado para que, se várias instâncias HandleErrorAttribute estiverem em vigor, não ocorra um log duplicado.

Eu simplesmente verifico context.ExceptionHandled antes de invocar a class base, apenas para saber se alguém lidou com a exceção antes do manipulador atual.
Funciona para mim e eu posto o código no caso de alguém mais precisar e para perguntar se alguém sabe se eu ignorei alguma coisa.

Espero que seja ú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); }