Wie kann ELMAH mit dem ASP.NET MVC -Attribut arbeiten?

Ich versuche, ELMAH zu verwenden, um Fehler in meiner ASP.NET MVC-Anwendung zu protokollieren. Wenn ich jedoch das [HandleError] -Attribut auf meinen Controllern verwende, protokolliert ELMAH keine Fehler, wenn sie auftreten.

Wie ich vermute, weil ELMAH nur unbehandelte Fehler protokolliert und das [HandleError] -Attribut den Fehler behandelt, so dass es nicht nötig ist, es zu protokollieren.

Wie ändere ich oder wie würde ich das Attribut ändern, so dass ELMAH wissen könnte, dass ein Fehler aufgetreten ist, und ihn protokollieren.

Edit: Lassen Sie mich sicherstellen, dass jeder versteht, ich weiß, dass ich das Attribut ändern kann, das ist nicht die Frage, die ich stelle … ELMAH wird umgangen, wenn das Attribut handlerror verwendet wird, was bedeutet, dass es einen Fehler gab, weil es behandelt wurde bereits durch das Attribut … Was ich frage ist, gibt es eine Möglichkeit, ELMAH den Fehler zu sehen und zu protokollieren, obwohl das Attribut es gehandhabt hat … Ich suchte herum und sehe keine Methoden, um es zum Loggen zu zwingen der Fehler….

Sie können HandleErrorAttribute Unterklasse HandleErrorAttribute und dessen OnException HandleErrorAttribute überschreiben (keine Notwendigkeit zum Kopieren), damit die Ausnahme mit ELMAH protokolliert wird, und nur dann, wenn die Basisimplementierung sie verarbeitet. Die minimale Menge an Code, die Sie benötigen, ist wie folgt:

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

Die Basisimplementierung wird zuerst aufgerufen, wodurch sie die Möglichkeit erhält, die Ausnahme als behandelt zu markieren. Nur dann wird die Ausnahme signalisiert. Der obige Code ist einfach und kann Probleme verursachen, wenn er in einer Umgebung verwendet wird, in der der HttpContext möglicherweise nicht verfügbar ist (z. B. beim Testen). Als Ergebnis werden Sie Code, der defensiver ist (auf Kosten von etwas länger) wollen:

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

Diese zweite Version wird versuchen, zuerst die Fehlersignalisierung von ELMAH zu verwenden, die die vollständig konfigurierte Pipeline wie Logging, Mailing, Filterung und was Sie haben, beinhaltet. Andernfalls versucht es zu sehen, ob der Fehler gefiltert werden soll. Wenn nicht, wird der Fehler einfach protokolliert. Diese Implementierung verarbeitet keine E-Mail-Benachrichtigungen. Wenn die Ausnahme signalisiert werden kann, wird eine E-Mail gesendet, sofern sie dafür konfiguriert wurde.

Sie müssen möglicherweise auch darauf achten, dass, wenn mehrere HandleErrorAttribute Instanzen in Kraft sind, doppelte Protokollierung nicht auftritt, aber die obigen zwei Beispiele sollten Sie HandleErrorAttribute .

Entschuldigung, aber ich denke, die akzeptierte Antwort ist ein Overkill. Alles, was Sie tun müssen, ist dies:

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

und dann registrieren Sie es (Reihenfolge ist wichtig) in Global.asax.cs:

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

Es gibt jetzt ein ELMAH.MVC-Paket in NuGet, das eine verbesserte Lösung von Atif enthält und auch einen Controller, der die Elmah-Schnittstelle innerhalb des MVC-Routings abwickelt (keine Notwendigkeit mehr, diese axd zu verwenden).
Das Problem mit dieser Lösung (und mit allen hier) ist, dass der Elmah-Fehlerhandler den Fehler tatsächlich behandelt und ignoriert, was Sie als customError-Tag oder durch ErrorHandler oder Ihren eigenen Fehlerhandler einrichten möchten
Die beste Lösung IMHO ist es, einen Filter zu erstellen, der am Ende aller anderen Filter agiert und die Ereignisse protokolliert, die bereits behandelt wurden. Das elmah-Modul sollte sich um die weiteren Fehler kümmern, die von der Anwendung nicht behandelt werden. Dies ermöglicht Ihnen auch, den Integritätsmonitor und alle anderen Module zu verwenden, die zu asp.net hinzugefügt werden können, um Fehlerereignisse anzuzeigen

Ich habe dies mit Reflektor auf den ErrorHandler in elmah.mvc geschrieben

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

Nun möchten Sie in Ihrer Filterkonfiguration so etwas tun:

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

Beachten Sie, dass ich dort einen Kommentar hinterlassen habe, um Leute daran zu erinnern, dass wenn Sie einen globalen Filter hinzufügen wollen, der die Ausnahme behandelt, VOR dem letzten Filter gehen sollte, sonst wird der Fall angezeigt, wo die unbehandelte Ausnahme von ElmahMVCErrorFilter ignoriert wird Es wurde nicht behandelt und es sollte vom Elmah-Modul gespeichert werden, aber dann markiert der nächste Filter die Ausnahme als behandelt und das Modul ignoriert sie, was dazu führt, dass die Ausnahme niemals in elmah übergeht.

Stellen Sie nun sicher, dass die Appsettings für elmah in Ihrer Webconfig etwa so aussehen:

           

Der wichtigste hier ist “elmah.mvc.disableHandleErrorFilter”, wenn dies falsch ist, wird der Handler in elmah.mvc verwendet, der die Ausnahme tatsächlich behandelt, indem er den Standard-HandleErrorHandler verwendet, der Ihre customError-Einstellungen ignoriert

Mit dieser Konfiguration können Sie Ihre eigenen ErrorHandler-Tags in classn und Ansichten festlegen, während Sie diese Fehler weiterhin über ElmahMVCErrorFilter protokollieren, eine customError-Konfiguration zu Ihrer web.config über das elmah-Modul hinzufügen und sogar Ihre eigenen Error-Handler schreiben. Sie müssen nur daran denken, keine Filter hinzuzufügen, die den Fehler vor dem von uns geschriebenen Elmah-Filter behandeln. Und ich habe vergessen zu erwähnen: keine Duplikate in Elmah.

Sie können den obigen Code verwenden und einen Schritt weiter gehen, indem Sie eine benutzerdefinierte Controller-Factory einführen, die das Attribut HandleErrorWithElmah in jeden Controller einfügt.

Weitere Informationen finden Sie in meiner Blog-Serie zum Einloggen in MVC. Der erste Artikel behandelt, wie Elmah für MVC eingerichtet und betrieben wird.

Es gibt einen Link zum herunterladbaren Code am Ende des Artikels. Ich hoffe, das hilft.

http://dotnetdarren.wordpress.com/

Ich bin neu in ASP.NET MVC. Ich habe das gleiche Problem, das folgende ist meine Workable in meinem Erorr.vbhtml (es funktioniert, wenn Sie nur den Fehler mit Elmah Protokoll protokollieren müssen)

 @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 ist einfach!

Eine vollständig alternative Lösung besteht darin, das MVC- HandleErrorAttribute nicht zu verwenden und stattdessen auf die ASP.Net-Fehlerbehandlung zu vertrauen, für die Elmah entwickelt wurde.

Sie müssen das standardmäßige globale HandleErrorAttribute aus App_Start \ FilterConfig (oder Global.asax) entfernen und anschließend in Ihrer Web.config eine Fehlerseite einrichten:

  

Beachten Sie, dass es sich hierbei um eine MVC-URL handelt, die weitergeleitet wird, sodass die oben genannten ErrorController.Index bei ErrorController.Index eines Fehlers zur ErrorController.Index Aktion umgeleitet werden.

Für mich war es sehr wichtig, dass die E-Mail-Protokollierung funktioniert. Nach einiger Zeit stelle ich fest, dass dies nur 2 Zeilen Code mehr in Atif benötigt.

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

Ich hoffe, das wird jemandem helfen 🙂

Dies ist genau das, was ich für meine MVC-Site-Konfiguration benötigt habe!

Ich habe der OnException Methode eine kleine Änderung OnException , um mehrere HandleErrorAttribute Instanzen zu behandeln, wie von Atif Aziz vorgeschlagen:

HandleErrorAttribute Sie, dass Sie möglicherweise darauf achten müssen, dass bei mehreren HandleErrorAttribute Instanzen keine doppelte Protokollierung erfolgt.

Ich überprüfe einfach context.ExceptionHandled vor dem Aufruf der Basisklasse, nur um zu wissen, ob jemand anderes die Ausnahme vor dem aktuellen Handler behandelt hat.
Es funktioniert für mich und ich poste den Code für den Fall, dass jemand anders es braucht und fragt, ob jemand weiß, ob ich irgendetwas übersehen habe.

Hoffe es ist nützlich:

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