Question

Je recherche une solution simple pour la journalisation des exceptions associée à la gestion des erreurs dans mon application ASP.Net MVC 1.0.

J'ai lu de nombreux articles, y compris les questions postées ici sur StackOverflow, qui proposent des solutions variées pour différentes situations. Je ne parviens toujours pas à trouver une solution adaptée à mes besoins.

Voici mes exigences:

  1. Pour pouvoir utiliser l'attribut [HandleError] (ou quelque chose d'équivalent) sur mon contrôleur, gérer toutes les exceptions pouvant être levées à partir de l'une des actions ou des vues. Cela devrait gérer toutes les exceptions qui n'ont pas été traitées spécifiquement pour l'une des actions (comme décrit au point 2). J'aimerais pouvoir spécifier à quelle vue un utilisateur doit être redirigé en cas d'erreur, pour toutes les actions du contrôleur.

  2. Je veux pouvoir spécifier l'attribut [HandleError] (ou quelque chose d'équivalent) en haut d'actions spécifiques pour intercepter des exceptions spécifiques et rediriger les utilisateurs vers une vue correspondant à l'exception. Toutes les autres exceptions doivent toujours être gérées par l'attribut [HandleError] sur le contrôleur.

  3. Dans les deux cas ci-dessus, je souhaite que les exceptions soient consignées à l'aide de log4net (ou de toute autre bibliothèque de journalisation).

Comment puis-je y parvenir? J'ai lu comment faire en sorte que tous mes contrôleurs héritent d'un contrôleur de base qui remplace la méthode OnException et dans lequel je consulte. Toutefois, cela entraînera des problèmes de redirection des utilisateurs vers les vues appropriées, ou le rendra compliqué.

J'ai lu des articles sur l'écriture de ma propre action de filtrage qui implémente IExceptionFilter pour gérer cela, mais cela sera en conflit avec l'attribut [HandleError].

Jusqu'à présent, je pense que la meilleure solution consiste à écrire mon propre attribut qui hérite de HandleErrorAttribute. De cette façon, je reçois toutes les fonctionnalités de [HandleError] et je peux ajouter ma propre journalisation log4net. La solution est la suivante:

    public class HandleErrorsAttribute: HandleErrorAttribute {

      private log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

      public override void OnException(ExceptionContext filterContext)
      {
          if (filterContext.Exception != null)
          {
            log.Error("Error in Controller", filterContext.Exception);
          }

          base.OnException(filterContext);
      }
   }

Le code ci-dessus convient-il à mes besoins? Si non, quelle solution répond à mes besoins?

Était-ce utile?

La solution

Je suis toujours un peu confus avec les différentes solutions existantes et avec la façon dont les attributs peuvent interférer les uns avec les autres, mais je suis allé avec cette solution:

public class LogErrorsAttribute: FilterAttribute, IExceptionFilter
{
    #region IExceptionFilter Members

    void IExceptionFilter.OnException(ExceptionContext filterContext)
    {
        if (filterContext != null && filterContext.Exception != null)
        {
            string controller = filterContext.RouteData.Values["controller"].ToString();
            string action = filterContext.RouteData.Values["action"].ToString();
            string loggerName = string.Format("{0}Controller.{1}", controller, action);

            log4net.LogManager.GetLogger(loggerName).Error(string.Empty, filterContext.Exception);
        }

    }

    #endregion
}

J'utilise toujours l'attribut [HandleError] comme expliqué dans la question d'origine et je décore simplement chaque contrôleur avec un attribut [LogErrors].

Cela fonctionne pour moi, car cela permet de consigner les erreurs au même endroit et ne provoque pas la journalisation des exceptions en double (ce qui se produira si j'étends [HandleError] et utilise l'attribut à plusieurs endroits).

Je ne pense pas qu'il sera possible de combiner la consignation des exceptions et la gestion des erreurs en un seul attribut ou classe, sans que cela devienne très fastidieux et complexe, ou que l'utilisation de [HandleError] ne soit pas affectée.

Mais cela fonctionne pour moi puisque je décore chaque contrôleur une seule fois, avec l'attribut [LogErrors], et décore les contrôleurs et les actions avec [HandleError] exactement comme je le veux, sans qu'ils ne se gênent mutuellement.

Mise à jour:

Voici un exemple d'utilisation de ce logiciel:

[LogErrors(Order = 0)]
[HandleError(Order = 99)]
public class ContactController : Controller
{
    public ActionResult Index()
    {
        return View(Views.Index);
    }

    public ActionResult Directions()
    {
        return View(Views.Directions);
    }


    public ActionResult ContactForm()
    {
        FormContactMessage formContactMessage = new FormContactMessage();

        return View(Views.ContactForm,formContactMessage);
    }

    [HandleError(ExceptionType = typeof(SmtpException), View = "MessageFailed", Order = 1)]
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult ContactForm(FormContactMessage formContactMessage)
    {
        if (ModelState.IsValid)
        {
            if (formContactMessage.IsValid)
            {
                SmtpClient client = new SmtpClient();

                MailAddress recipientAddress = new MailAddress(Properties.Settings.Default.ContactFormRecipientEmailAddress);
                MailAddress senderAddress = new MailAddress(Properties.Settings.Default.ContactFormSenderEmailAddress);
                MailMessage mailMessage = formContactMessage.ToMailMessage(recipientAddress, senderAddress);

                client.Send(mailMessage);

                return View("MessageSent");
            }
            else
            {
                ModelState.AddRuleViolations(formContactMessage.GetRuleViolations());
            }
        }
        return View(Views.ContactForm, formContactMessage);
    }

    private static class Views
    {
        public static string Index { get { return "Index"; } }
        public static string Directions { get { return "Directions"; } }
        public static string ContactForm { get { return "ContactForm"; } }

    }
}

Dans le code ci-dessus, les exceptions SmtpExceptions de la surcharge d'action ContactForm sont gérées de manière très spécifique: l'utilisateur reçoit une ViewPage spécifique aux messages envoyés qui ont échoué, elle est appelée " MessageFailed " . Toutes les autres exceptions sont gérées par le comportement par défaut de [HandleError]. Notez également que la consignation des erreurs a lieu en premier, suivie du traitement des erreurs. Ceci est indiqué par ce qui suit:

[LogErrors(Order = 0)]
[HandleError(Order = 99)]

Mise à jour:

Il existe une solution alternative à cela, avec une très bonne explication. Je recommande de le parcourir pour mieux comprendre les problèmes en jeu.

Attribut ASP.NET MVC HandleError, pages d'erreur personnalisées et journalisation des exceptions (Merci à Scott Shepherd ci-dessous, qui a fourni le lien dans une réponse ci-dessous).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top