573 Stimmen

Wie kann ELMAH mit dem ASP.NET MVC [HandleError] Attribut verwendet werden?

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

Ich vermute, dass ELMAH nur nicht behandelte Fehler protokolliert und das [HandleError]-Attribut den Fehler behandelt, sodass kein Bedarf besteht, ihn zu protokollieren.

Wie kann ich das Attribut modifizieren oder wie könnte ich vorgehen, um das Attribut so zu ändern, dass ELMAH erkennt, dass ein Fehler aufgetreten ist und ihn protokolliert..

Bearbeitung: Ich möchte sicherstellen, dass jeder versteht, ich weiß, dass ich das Attribut modifizieren kann, das ist nicht die Frage, die ich stelle... ELMAH wird umgangen, wenn das HandleError-Attribut verwendet wird, was bedeutet, dass es nicht sieht, dass ein Fehler aufgetreten ist, weil er bereits vom Attribut behandelt wurde... Was ich frage ist, ob es eine Möglichkeit gibt, ELMAH den Fehler sehen und protokollieren zu lassen, auch wenn das Attribut ihn behandelt hat... Ich habe gesucht und keine Methoden gefunden, um es zu zwingen, den Fehler zu protokollieren....

12 Stimmen

Wow, ich hoffe, Jeff oder Jared würden diese Frage beantworten. Sie verwenden ELMAH für Stackoverflow ;)

11 Stimmen

Hmm, seltsam - wir verwenden den HandleErrorAttribute nicht - Elmah ist in unserem -Bereich von web.config eingerichtet. Gibt es Vorteile bei der Verwendung des HandleErrorAttribute?

1 Stimmen

Nun ja, ich glaube, du bekommst diese lästige Abfragezeichenfolge nicht in der URL, und wenn ein Fehler auftritt, wird die URL nicht auf die im benutzerdefinierten Fehler im web.config angegebene umgeleitet... für mich einfach sauberer

511voto

Atif Aziz Punkte 35092

Sie können die HandleErrorAttribute unterordnen und ihr OnException Member überschreiben (nicht nötig zu kopieren), damit es die Ausnahme mit ELMAH protokolliert und nur, wenn die Basimplementierung damit umgeht. Der minimale Code, den Sie benötigen, lautet 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 Basimplementierung wird zuerst aufgerufen, um ihr die Möglichkeit zu geben, die Ausnahme als behandelt zu markieren. Erst dann wird die Ausnahme signalisiert. Der obige Code ist einfach und kann Probleme verursachen, wenn er in einer Umgebung verwendet wird, in der das HttpContext möglicherweise nicht verfügbar ist, wie z.B. bei Tests. Daher möchten Sie Code, der defensiver ist (zum Preis von etwas längerem Code):

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       // wenn nicht behandelt wird trotzdem protokolliert
            || TryRaiseErrorSignal(context) // bevorzugen Signalisierung, wenn möglich
            || IsFiltered(context))         // gefiltert?
            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;
    }
}

Bei dieser zweiten Version wird zuerst versucht, die Fehler-Signalisierung von ELMAH zu verwenden, was den vollständig konfigurierten Pipeline wie Protokollierung, E-Mail-Versand, Filterung und vieles mehr umfasst. Falls dies fehlschlägt, wird geprüft, ob der Fehler gefiltert werden soll. Wenn nicht, wird der Fehler einfach protokolliert. Diese Implementierung behandelt keine E-Mail-Benachrichtigungen. Wenn die Ausnahme signalisiert werden kann, wird eine E-Mail gesendet, wenn dies so konfiguriert ist.

Sie müssen auch darauf achten, dass bei mehreren HandleErrorAttribute-Instanzen keine doppelte Protokollierung erfolgt, aber die obigen beiden Beispiele sollten Sie auf den richtigen Weg bringen.

0 Stimmen

Ich kann ElmahHandleErrorAttribute nicht zum Laufen bringen. Meine aktuelle Konfiguration funktioniert gut mit Elmah in Modulen und Handlern. Ich habe [HandleError] aus meinen Controllern entfernt. Ich möchte versuchen, ElmahHandleErrorAttribute zu verwenden. Ich habe ElmahHandleErrorAttribute auf meinen ApplicationController (die Basisklasse aller meiner Controller) gesetzt, aber es wird nie aufgerufen, wenn ich debugge und einen Breakpoint in OnException setze. Was fehlt mir?

1 Stimmen

Ausgezeichnet. Ich habe überhaupt nicht versucht, Elmah zu implementieren. Ich habe nur versucht, meine eigene Fehlermeldung anzuschließen, die ich seit Jahren benutze, auf eine Weise, die gut mit MVC funktioniert. Ihr Code hat mir einen Ausgangspunkt gegeben. +1

0 Stimmen

Vielen Dank. Ich dachte, ich verliere meinen Verstand, als ich tatsächlich das Verhalten "HandleError wird ignoriert, wenn customErrors auf RemoteOnly eingestellt ist und Sie sich auf dem localhost befinden" beobachtete. Es stellte sich heraus, dass der Code in meinem Application_Error-Ereignis umsonst war!

305voto

Ivan Zlatev Punkte 12466

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

public class ElmahHandledErrorLoggerFilter : IExceptionFilter
{
    public void OnException (ExceptionContext context)
    {
        // Nur behandelte Ausnahmen protokollieren, da alle anderen sowieso von ELMAH erfasst werden.
        if (context.ExceptionHandled)
            ErrorSignal.FromCurrentContext().Raise(context.Exception);
    }
}

und dann im Global.asax.cs registrieren (Reihenfolge ist wichtig):

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

3 Stimmen

+1 Sehr schön, es ist nicht erforderlich, das HandleErrorAttribute zu erweitern, es ist nicht erforderlich, OnException auf BaseController zu überschreiben. Dies sollte die akzeptierte Antwort sein.

0 Stimmen

@Ivan Zlatev, hast du Ideen, wie man in solchen Fällen eine Flagge oder eine Fehlermeldung voranstellen kann, um im Elmah Fehlerprotokoll festzustellen/sehen zu können, welche Fehler behandelt wurden und welche nicht?

1 Stimmen

@bigb Ich denke, du müsstest die Ausnahme in deinem eigenen Ausnahmetyp umschließen, um Dinge an die Ausnahmemeldung anzuhängen usw. (z. B. `new UnhandledLoggedException(Ausnahme geworfen)`, das etwas an das `Nachricht` anhängt, bevor es zurückgegeben wird.

16voto

Raul Vejar Punkte 827

Jetzt gibt es ein ELMAH.MVC-Paket in NuGet, das eine verbesserte Lösung von Atif enthält und auch einen Controller, der die elmah-Schnittstelle innerhalb der MVC-Routing (keine Notwendigkeit mehr, diese axd zu verwenden) behandelt.
Das Problem bei dieser Lösung (und bei allen anderen hier) ist, dass die elmah-Fehlerbehandlung auf die eine oder andere Weise tatsächlich den Fehler behandelt und dabei ignoriert, was Sie möglicherweise als benutzerdefiniertes customError-Tag oder durch ErrorHandler oder Ihren eigenen Fehlerbehandler festlegen möchten.
Die beste Lösung meiner Meinung nach besteht darin, einen Filter zu erstellen, der am Ende aller anderen Filter agiert und die bisher behandelten Ereignisse protokolliert. Das elmah-Modul sollte sich um die Protokollierung der anderen Fehler kümmern, die von der Anwendung nicht behandelt werden. Dadurch können Sie auch den Health Monitor und alle anderen Module verwenden, die in asp.net hinzugefügt werden können, um Fehlerereignisse zu betrachten

Das habe ich geschrieben, als ich mit Reflektor auf den ErrorHandler innerhalb von elmah.mvc geschaut habe

public class ElmahMVCErrorFilter : IExceptionFilter
{
   private static ErrorFilterConfiguration _config;

   public void OnException(ExceptionContext context)
   {
       if (context.ExceptionHandled) //Die nicht behandelten werden vom elmah-Modul aufgegriffen
       {
           var e = context.Exception;
           var context2 = context.HttpContext.ApplicationInstance.Context;
           //TODO: Zusätzliche Variablen zu context.HttpContext.Request.ServerVariables für behandelte und nicht behandelte Ausnahmen hinzufügen
           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;
   }
}

Jetzt möchten Sie in Ihrer Filterkonfiguration etwas Ähnliches tun:

    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        //Diese Filter sollten am Ende der Pipeline stehen, fügen Sie alle Fehlerbehandler vorher hinzu
        filters.Add(new ElmahMVCErrorFilter());
    }

Beachten Sie, dass ich dort einen Kommentar hinterlassen habe, um die Leute daran zu erinnern, dass, wenn sie einen globalen Filter hinzufügen möchten, der tatsächlich die Ausnahme behandelt, dieser VOR diesem letzten Filter platziert werden sollte, da Sie sonst in den Fall geraten, dass die unbehandelte Ausnahme vom ElmahMVCErrorFilter ignoriert wird, weil sie nicht behandelt wurde und vom Modul protokolliert werden sollte, aber dann markiert der nächste Filter die Ausnahme als behandelt und das Modul ignoriert sie, was dazu führt, dass die Ausnahme nie in elmah ankommt.

Vergewissern Sie sich nun, dass die appsettings für elmah in Ihrem Web.config so ähnlich wie folgt aussehen:

Der wichtige hier ist "elmah.mvc.disableHandleErrorFilter", wenn dies falsch ist, wird der Handler innerhalb elmah.mvc verwendet, der tatsächlich die Ausnahme behandelt, indem der Standard-HandleErrorHandler verwendet wird, der Ihre benutzerdefinierten Error-Einstellungen ignoriert

Mit dieser Konfiguration können Sie Ihre eigenen ErrorHandler-Tags in Klassen und Ansichten festlegen, während Sie diese Fehler durch den ElmahMVCErrorFilter protokollieren, eine benutzerdefinierte Error-Konfiguration in Ihrer Web.config durch das elmah-Modul hinzufügen, sogar Ihre eigenen Error-Handler schreiben. Das Einzige, was Sie tun müssen, ist daran zu denken, keine Filter hinzuzufügen, die den Fehler tatsächlich vor dem von uns geschriebenen elmah-Filter behandeln. Und ich habe vergessen zu erwähnen: keine Duplikate in elmah.

9voto

Darren Punkte 337

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

Weitere Informationen finden Sie in meiner Blog-Serie zum Protokollieren in MVC. Der erste Artikel behandelt die Einrichtung und Ausführung von Elmah für MVC.

Am Ende des Artikels gibt es einen Link zum herunterladbaren Code. Ich hoffe, das hilft.

http://dotnetdarren.wordpress.com/

6 Stimmen

Es scheint mir, als wäre es viel einfacher, es einfach auf einer Basis-Controller-Klasse zu platzieren!

2 Stimmen

Darrens Serie oben zum Thema Protokollierung und Fehlerbehandlung ist auf jeden Fall lesenswert!!! Sehr gründlich!

8voto

Ross McNab Punkte 10829

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 globale Standard-HandleErrorAttribute aus App_Start\FilterConfig (oder Global.asax) entfernen und dann eine Fehlerseite in Ihrer Web.config einrichten:

Hinweis: Dies kann eine MVC-geroutete URL sein, daher würde dies zu der ErrorController.Index-Aktion umleiten, wenn ein Fehler auftritt.

0 Stimmen

Das ist mit Abstand die einfachste Lösung, und die Standardumleitung kann eine MVC-Aktion sein :)

3 Stimmen

Das wird für andere Arten von Anfragen umleiten, wie JSON usw. - nicht gut.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X