Comment faire pour que ELMAH fonctionne avec l’atsortingbut ASP.NET MVC ?

J’essaie d’utiliser ELMAH pour consigner les erreurs dans mon application ASP.NET MVC. Cependant, lorsque j’utilise l’atsortingbut [HandleError] sur mes contrôleurs, ELMAH n’enregistre pas les erreurs lorsqu’elles se produisent.

Comme je suppose que c’est parce que ELMAH enregistre uniquement les erreurs non traitées et que l’atsortingbut [HandleError] gère l’erreur, il n’est donc pas nécessaire de le consigner.

Comment puis-je modifier ou comment puis-je modifier l’atsortingbut afin que ELMAH puisse savoir qu’il y a eu une erreur et l’enregistrer?

Edit: Laissez-moi m’assurer que tout le monde comprend, je sais que je peux modifier l’atsortingbut, ce n’est pas la question que je pose … ELMAH est contourné en utilisant l’atsortingbut handleerror, ce qui signifie qu’il ne verra pas une erreur déjà par l’atsortingbut … Ce que je demande, est-ce qu’il y a un moyen de faire en sorte que ELMAH voit l’erreur et la connecte même si l’atsortingbut l’a traitée … J’ai cherché autour et ne vois aucune méthode à appeler pour la forcer à se connecter l’erreur….

Vous pouvez sous- HandleErrorAtsortingbute et remplacer son membre OnException (pas besoin de copier) pour qu’il enregistre l’exception avec ELMAH et uniquement si l’implémentation de base la gère. La quantité minimale de code dont vous avez besoin est la suivante:

 using System.Web.Mvc; using Elmah; public class HandleErrorAtsortingbute : System.Web.Mvc.HandleErrorAtsortingbute { 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); } } 

L’implémentation de base est appelée en premier, ce qui lui permet de marquer l’exception comme étant gérée. Alors seulement l’exception est signalée. Le code ci-dessus est simple et peut entraîner des problèmes s’il est utilisé dans un environnement où le HttpContext peut ne pas être disponible, tel que testing. Par conséquent, vous voudrez un code plus défensif (au prix d’un peu plus long):

 using System.Web; using System.Web.Mvc; using Elmah; public class HandleErrorAtsortingbute : System.Web.Mvc.HandleErrorAtsortingbute { 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 essaiera d’utiliser d’abord la signalisation d’erreur d’ELMAH, qui implique le pipeline entièrement configuré, comme la journalisation, le mailing, le filtrage et ce que vous avez. À défaut, il tente de voir si l’erreur doit être filtrée. Sinon, l’erreur est simplement consignée. Cette implémentation ne gère pas les notifications par courrier. Si l’exception peut être signalée, un courrier sera envoyé si configuré pour le faire.

Si plusieurs instances de HandleErrorAtsortingbute sont en vigueur, vous devrez peut-être vous assurer que la HandleErrorAtsortingbute en double ne se produit pas, mais les deux exemples ci-dessus devraient vous permettre de démarrer.

Désolé, mais je pense que la réponse acceptée est exagérée. Tout ce que vous devez faire c’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 HandleErrorAtsortingbute()); } 

Il y a maintenant un paquet ELMAH.MVC dans NuGet qui inclut une solution améliorée d’Atif et aussi un contrôleur qui gère l’interface elmah dans le routage MVC (pas besoin d’utiliser cet axd)
Le problème avec cette solution (et avec tous ceux ici) est que le gestionnaire d’erreurs elmah gère l’erreur d’une manière ou d’une autre, ignorant ce que vous pourriez vouloir configurer en tant que balise customError ou ErrorHandler ou votre propre gestionnaire d’erreurs.
La meilleure solution IMHO consiste à créer un filtre qui agira à la fin de tous les autres filtres et enregistrera les événements déjà traités. Le module elmah doit veiller à enregistrer les autres erreurs non gérées par l’application. Cela vous permettra également d’utiliser le moniteur de santé et tous les autres modules pouvant être ajoutés à asp.net pour examiner les événements d’erreur.

J’ai écrit ceci en regardant avec le réflecteur au ErrorHandler dans 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 configuration de filtre, 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()); } 

Notez que j’y ai laissé un commentaire pour rappeler aux gens que s’ils veulent append un filtre global qui gérera réellement l’exception, il doit y avoir AVANT ce dernier filtre, sinon vous rencontrerez le cas où l’exception non gérée sera ignorée par ElmahMVCErrorFilter car il n’a pas été manipulé et il devrait être enregistré par le module Elmah, mais le filtre suivant marque l’exception comme étant gérée et le module l’ignore, ce qui fait que l’exception ne devient jamais elmah.

Maintenant, assurez-vous que les parameters d’application d’elmah dans votre configuration Web ressemblent à ceci:

           

L’important est “elmah.mvc.disableHandleErrorFilter”, si c’est faux, il utilisera le gestionnaire dans elmah.mvc qui gérera réellement l’exception en utilisant le HandleErrorHandler par défaut qui ignorera vos parameters customError

Cette configuration vous permet de définir vos propres balises ErrorHandler dans les classes et les vues, tout en continuant à consigner ces erreurs via ElmahMVCErrorFilter, en ajoutant une configuration customError à votre fichier web.config via le module elmah, en écrivant même vos propres gestionnaires d’erreur. La seule chose à faire est de ne pas append de filtres pour gérer l’erreur avant le filtre elmah que nous avons écrit. Et j’ai oublié de mentionner: pas de doublons dans elmah.

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

Pour plus d’informations, consultez ma série de blogs sur la connexion à MVC. Le premier article traite de 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/

Je suis nouveau dans ASP.NET MVC. J’ai rencontré le même problème, ce qui suit est mon travail dans mon Erorr.vbhtml (cela fonctionne si vous devez seulement enregistrer l’erreur en utilisant le journal 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 

Sorry, an error occurred while processing your request.
@item.ActionName
@item.ControllerName
@item.Exception.Message

C’est tout simplement!

Une solution totalement alternative consiste à ne pas utiliser MVC HandleErrorAtsortingbute , et à se fier à la gestion des erreurs ASP.Net, avec laquelle Elmah est conçu pour fonctionner.

Vous devez supprimer le HandleErrorAtsortingbute global par défaut de App_Start \ FilterConfig (ou Global.asax), puis configurer une page d’erreur dans votre fichier Web.config:

  

Notez que cela peut être une URL routée MVC, de sorte que ce qui précède serait redirigé vers l’action ErrorController.Index lorsqu’une erreur se produit.

Pour moi, il était très important que la journalisation du courrier électronique fonctionne. Après un certain temps, je découvre que cela nécessite seulement deux lignes de code dans l’exemple d’Atif.

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

J’espère que cela aidera quelqu’un 🙂

C’est exactement ce dont j’avais besoin pour la configuration de mon site MVC!

J’ai ajouté une petite modification à la méthode OnException pour gérer plusieurs instances de HandleErrorAtsortingbute , comme suggéré par Atif Aziz:

N’oubliez pas que si plusieurs instances de HandleErrorAtsortingbute sont en vigueur, la journalisation en double ne se produit pas.

Je vérifie simplement context.ExceptionHandled avant d’appeler la classe de base, juste pour savoir si quelqu’un d’autre a géré l’exception avant le gestionnaire actuel.
Cela fonctionne pour moi et je poste le code au cas où quelqu’un d’autre en aurait besoin et pour demander si quelqu’un sait si j’ai oublié quelque chose.

J’espère que c’est utile:

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