573 Stimmen

Wie kann man ELMAH dazu bringen, mit dem ASP.NET MVC [HandleError]-Attribut zu funktionieren?

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

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 ändern oder wie könnte ich das Attribut ändern, so dass ELMAH weiß, dass ein Fehler aufgetreten ist und ihn protokolliert.

Bearbeitung: 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 HandleError-Attribut verwendet wird, was bedeutet, dass es den Fehler nicht sieht, weil er bereits vom Attribut behandelt wurde... Was ich frage, ob es eine Möglichkeit gibt, ELMAH den Fehler sehen und protokollieren zu lassen, obwohl das Attribut ihn behandelt hat... Ich habe gesucht und keine Methoden gefunden, die aufgerufen werden könnten, um ihn dazu 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, komisch - wir verwenden nicht das HandleErrorAttribute - Elmah ist in unserem -Abschnitt der web.config eingerichtet. Gibt es Vorteile bei der Verwendung des HandleErrorAttribute?

1 Stimmen

Nun ja, ich glaube, dass du diese nervige Querystring-Abfrage nicht in der URL erhältst, und wenn ein Fehler auftritt, wird die URL nicht auf die im benutzerdefinierten Fehler im Web.config angegebene umgeleitet... für mich ist es einfach sauberer

511voto

Atif Aziz Punkte 35092

Sie können HandleErrorAttribute subklassifizieren und ihr OnException-Element überschreiben (keine Notwendigkeit zu kopieren), um die Ausnahme mit ELMAH zu protokollieren, und nur wenn die Basimplementierung damit umgeht. Der minimal erforderliche Code 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);
    }
}

Zuerst wird die Basimplementierung aufgerufen, um der Ausnahme die Möglichkeit zu geben, als behandelt markiert zu werden. 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 nicht verfügbar ist, wie z.B. beim Testen. Daher sollten Sie einen defensiveren Code verwenden (auf Kosten einer etwas längeren Variante):

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       // wird trotzdem protokolliert, wenn unbehandelt
            || TryRaiseErrorSignal(context) // bevorzugen Sie die 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;
    }
}

In dieser zweiten Version wird zuerst versucht, die Fehlermeldung von ELMAH zu verwenden, was den vollständig konfigurierten Pipeline wie Protokollierung, E-Mail-Benachrichtigung, Filterung und Ähnliches einschließt. Falls das nicht erfolgreich ist, wird überprüft, ob der Fehler gefiltert werden soll. Wenn nicht, wird der Fehler einfach protokolliert. Diese Implementierung handhabt keine E-Mail-Benachrichtigungen. Wenn die Ausnahme signalisiert werden kann, wird eine E-Mail gesendet, wenn dies konfiguriert ist.

Sie müssen auch darauf achten, dass bei mehreren HandleErrorAttribute-Instanzen keine doppelte Protokollierung auftritt, aber die obigen beiden Beispiele sollten Sie in Gang bringen.

0 Stimmen

Ich kann nicht ElmahHandleErrorAttribute 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, den ElmahHandleErrorAttribute zu verwenden. Ich habe den ElmahHandleErrorAttribute auf meine 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, die ich seit Jahren benutze, so anzuschließen, dass sie gut mit MVC funktioniert. Ihr Code hat mir einen Ausgangspunkt gegeben. +1

0 Stimmen

Vielen Dank. Ich dachte, ich werde verrückt, als ich tatsächlich das Verhalten "HandleError wird ignoriert, wenn customErrors auf RemoteOnly gesetzt sind 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

Tut mir leid, aber ich denke, die akzeptierte Antwort ist übertrieben. Alles, was du tun musst, ist folgendes:

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 registrieren (die Reihenfolge ist wichtig) in Global.asax.cs:

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

3 Stimmen

+1 Sehr schön, keine Notwendigkeit, das HandleErrorAttribute zu erweitern, keine Notwendigkeit, OnException in BaseController zu überschreiben. Dies sollte die akzeptierte Antwort sein.

0 Stimmen

@Ivan Zlatev habt Ihr Ideen, wie man in einem solchen Fall ein Flag oder eine Fehlermeldungsvorzeichen hinzufügen kann, um im Elmah-Fehlerprotokoll feststellen/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 zur Ausnahmemeldung hinzuzufügen usw. (zum Beispiel new UnhandledLoggedException(Ausnahme geworfen), das etwas an die Nachricht anhängt, bevor es zurückgegeben wird.

16voto

Raul Vejar Punkte 827

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 behandelt (keine Notwendigkeit mehr, dieses axd zu verwenden)
Das Problem bei dieser Lösung (und bei allen anderen hier) ist, dass auf die eine oder andere Weise der Elmah-Fehlerhandler tatsächlich den Fehler behandelt und ignoriert, was Sie möglicherweise als benutzerdefiniertes Fehler-Tag oder durch ErrorHandler oder Ihren eigenen Fehlerhandler festlegen möchten
Die beste Lösung ist meiner Meinung nach, einen Filter zu erstellen, der am Ende aller anderen Filter wirkt und die Ereignisse protokolliert, die bereits behandelt wurden. Das Elmah-Modul sollte sich um das Protokollieren der anderen Fehler kümmern, die von der Anwendung nicht behandelt werden. Dies ermöglicht es Ihnen auch, den Gesundheitsmonitor und alle anderen Module, die zu asp.net hinzugefügt werden können, zu verwenden, um Fehlerereignisse zu betrachten

Ich habe dies geschrieben, indem ich mir mit Reflektor den ErrorHandler innerhalb von elmah.mvc angesehen habe

public class ElmahMVCErrorFilter : IExceptionFilter
{
   private static ErrorFilterConfiguration _config;

   public void OnException(ExceptionContext context)
   {
       if (context.ExceptionHandled) //Die unbehandelten werden vom Elmah-Modul ausgewählt
       {
           var e = context.Exception;
           var context2 = context.HttpContext.ApplicationInstance.Context;
           //TODO: Fügen Sie zusätzliche Variablen zu context.HttpContext.Request.ServerVariables für behandelte und unbehandelte Ausnahmen hinzu
           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 wie folgt tun:

    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        //Diese Filter sollten am Ende des Pipelines stehen, fügen Sie alle Fehlerbehandler davor 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 stehen sollte, sonst geraten Sie in den Fall, dass die unbehandelte Ausnahme vom ElmahMVCErrorFilter ignoriert wird, da 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 landet.

Stellen Sie nun sicher, dass die App-Einstellungen für elmah in Ihrer Web.config so aussehen:

Der wichtige hier ist "elmah.mvc.disableHandleErrorFilter", wenn dies falsch ist, wird der Handler innerhalb von Elmah.Mvc verwendet, der tatsächlich die Ausnahme behandelt, indem er den Standard HandleErrorHandler verwendet, der Ihre customError-Einstellungen ignoriert

Diese Konfiguration ermöglicht es Ihnen, Ihre eigenen ErrorHandler-Tags in Klassen und Ansichten festzulegen, während Sie diese Fehler durch den ElmahMVCErrorFilter protokollieren, eine customError-Konfiguration über das Elmah-Modul zu Ihrer Web.config hinzufügen, sogar Ihre eigenen Fehlerhandler schreiben. Das einzige, was Sie tun müssen, ist daran zu denken, keine Filter hinzuzufügen, die tatsächlich den Fehler behandeln, bevor der von uns geschriebene Elmah-Filter hinzugefügt wird. 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. Im ersten Artikel wird erläutert, wie Elmah für MVC eingerichtet und ausgeführt wird.

Am Ende des Artikels finden Sie 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 an eine Basiskontrollerklasse anzuhängen!

2 Stimmen

Darrens Serie oben über das Protokollieren und die Ausnahmebehandlung lohnt sich auf jeden Fall zu lesen!!! 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 ASP.Net-Fehlerbehandlung zu setzen, die mit Elmah zusammenarbeitet.

Sie müssen das standardmäßige globale 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 das obige Beispiel zur ErrorController.Index Aktion umleiten, wenn ein Fehler auftritt.

0 Stimmen

Dies 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 z.B. 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