562 votes

Comment faire fonctionner ELMAH avec l'attribut ASP.NET MVC [HandleError]?

Je suis en train d'utiliser ELMAH pour consigner les erreurs dans mon ASP.NET application MVC, cependant quand j'utilise le [HandleError] attribut sur mon contrôleurs en apparence, rien ne journal des erreurs lorsqu'elles se produisent.

Comme je suppose que c'est parce que ELMAH seulement les journaux d'erreurs non gérées et l' [HandleError] attribut est de la manipulation de l'erreur et donc pas besoin de connexion.

Comment puis-je modifier ou comment pourrais-je aller sur la modification de l'attribut de sorte que ELMAH peut savoir qu'il y avait une erreur et l'enregistrer..

Edit: Permettez-moi de vous assurer que tout le monde comprend, je sais que je peux modifier l'attribut qui n'est pas la question que je pose la question... ELMAH obtient contournée lors de l'utilisation de la handleerror attribut sens de ne pas voir qu'il y avait une erreur, car il a été traité déjà par l'attribut... Ce que je demande est-il un moyen de faire ELMAH voir l'erreur et de l'enregistrer même si l'attribut réagi...j'ai cherché partout et je ne vois pas toutes les méthodes à appeler pour le forcer à enregistrer l'erreur....

501voto

Atif Aziz Points 16967

Vous pouvez sous-classe HandleErrorAttribute et de remplacer son OnException membre (pas besoin de copie) de sorte qu'il enregistre l'exception avec ELMAH, et seulement si la base de la mise en œuvre des poignées. Le montant minimal de code que vous avez besoin est comme suit:

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

La base de la mise en œuvre est d'abord appelée, lui donner une chance de marque de l'exception que de le manipuler. C'est uniquement à l'exception signalée. Le code ci-dessus est simple et peut causer des problèmes si elle est utilisée dans un environnement où l' HttpContext peuvent ne pas être disponibles, tels que les tests. Comme un résultat, vous voulez le code, c'est que plus défensif (au prix d'être légèrement plus long):

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

Cette deuxième version, essayez de l'utiliser signalisation d'erreur de ELMAH en premier, ce qui implique entièrement configuré de pipeline comme l'exploitation forestière, de diffusion, de filtrage et de ce que vous avez. À défaut, il tente de voir si l'erreur doit être filtrée. Si non, l'erreur est simplement connecté. Cette application ne gère pas les notifications par mail. Si l'exception peut être signalé ensuite un mail vous sera envoyé si il est configuré pour le faire.

Vous pouvez également avoir à prendre en charge que si plusieurs HandleErrorAttribute instances sont en effet en double enregistrement ne se produit pas, mais les deux exemples ci-dessus devrait obtenir votre commencé.

297voto

Ivan Zlatev Points 4844

Désolé, mais je pense que la réponse acceptée est une overkill. Tout ce que vous devez faire est ceci:

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

puis enregistrez-le (l'ordre est important) dans Global.asax.cs:

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

14voto

Raul Vejar Points 514

Il y a maintenant un ELMAH.MVC package NuGet qui inclut une amélioration de la solution par Atif et également un contrôleur qui gère le elmah interface MVC de routage (pas besoin d'utiliser cette axd plus)
Le problème avec cette solution (et avec tous ceux ici) est que, d'une façon ou d'une autre la elmah gestionnaire d'erreur est en fait de la manipulation de l'erreur, en ignorant ce que vous voulez définir en tant que customError tag ou par l'intermédiaire de ErrorHandler ou de votre propre gestionnaire d'erreur
La meilleure solution à mon humble avis est de créer un filtre de loi à la fin de tous les autres filtres et de consigner les événements qui ont été déjà traitées. Le elmah module doit prendre soin de loging les autres erreurs non gérées par l'application. Cela vous permettra également d'utiliser le moniteur de la santé et tous les autres modules qui peuvent être ajoutés à asp.net à regarder les événements d'erreur

J'ai écrit cette recherche avec réflecteur à la ErrorHandler à l'intérieur de 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;
   }
}

Maintenant, dans votre filtre config que vous voulez faire quelque chose comme ceci:

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

L'avis que j'ai laissé un commentaire pour rappeler aux gens que s'ils veulent ajouter un filtre global qui va gérer l'exception, il faut aller de l'AVANT de ce dernier filtre, sinon, vous courez dans le cas où l'exception non gérée seront ignorés par le ElmahMVCErrorFilter parce qu'il n'a pas été manipulé et qu'il doit être interjeté par le Elmah module, mais ensuite le filtre suivant les marques de l'exception, comme manipulés et le module ignore, résultant de l'exception ne jamais en faire elmah.

Maintenant, assurez-vous que le appsettings pour elmah dans votre webconfig ressembler à quelque chose comme ceci:

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

L'important ici est "elmah.mvc.disableHandleErrorFilter", si c'est faux, il va utiliser le gestionnaire à l'intérieur de elmah.mvc qui va gérer l'exception en utilisant la valeur par défaut HandleErrorHandler qui ignore votre customError paramètres

Cette configuration vous permet de définir votre propre ErrorHandler balises dans les classes et les points de vue, tout en continuant de loging ces erreurs par le biais de la ElmahMVCErrorFilter, l'ajout d'un customError configuration de votre site web.config à travers le elmah module, même l'écriture de vos propres Gestionnaires d'Erreur. La seule chose que vous devez faire est de se rappeler de ne pas ajouter des filtres qui va gérer l'erreur avant la elmah filtres que nous avons écrit. Et j'ai oublié de mentionner: pas de doublons dans elmah.

7voto

Darren Points 194

Vous pouvez prendre le code ci-dessus et aller plus loin en introduisant une fabrique de contrôleurs personnalisés qui injecte l'attribut HandleErrorWithElmah dans chaque contrôleur.

Pour plus d'informations, consultez ma série de blogs sur la connexion à MVC. Le premier article couvre la mise en place d'Elmah pour MVC.

Il y a un lien vers le code téléchargeable à la fin de l'article. J'espère que cela pourra aider.

http://dotnetdarren.wordpress.com/

6voto

user716264 Points 87

Je suis nouveau dans ASP.NET MVC. J'ai fait face au même problème, ce qui suit est mon réalisable dans mon Erorr.vbhtml (cela fonctionne si vous avez seulement besoin de vous connecter l'erreur en utilisant le journal d'Elmah)

 @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

<h2>
    Sorry, an error occurred while processing your request.<br />

    @item.ActionName<br />
    @item.ControllerName<br />
    @item.Exception.Message
</h2> 
 

C'est simplement!

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X