asp.net-mvc - net - mvc error page




Wie kann ELMAH mit dem ASP.NET MVC[HandleError]-Attribut arbeiten? (6)

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

Ich versuche ELMAH zu verwenden, um Fehler in meiner ASP.NET MVC-Anwendung zu protokollieren. Wenn ich jedoch das Attribut [HandleError] 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 notwendig 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....


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:

<customErrors mode="RemoteOnly" defaultRedirect="~/error/" />

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.


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 geladen 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:

<add key="elmah.mvc.disableHandler" value="false" /> <!-- This handles elmah controller pages, if disabled elmah pages will not work -->
<add key="elmah.mvc.disableHandleErrorFilter" value="true" /> <!-- This uses the default filter for elmah, set to disabled to use our own -->
<add key="elmah.mvc.requiresAuthentication" value="false" /> <!-- Manages authentication for elmah pages -->
<add key="elmah.mvc.allowedRoles" value="*" /> <!-- Manages authentication for elmah pages -->
<add key="elmah.mvc.route" value="errortracking" /> <!-- Base route for elmah pages -->

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 Klassen 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.


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 :)


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/


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 .





elmah