108 votes

Consignation des erreurs dans ASP.NET MVC

J'utilise actuellement log4net dans mon application ASP.NET MVC pour enregistrer les exceptions. Pour ce faire, je fais en sorte que tous mes contrôleurs héritent d'une classe BaseController. Dans l'événement OnActionExecuting de BaseController, je consigne toutes les exceptions qui ont pu se produire :

protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
    // Log any exceptions
    ILog log = LogManager.GetLogger(filterContext.Controller.GetType());

    if (filterContext.Exception != null)
    {
        log.Error("Unhandled exception: " + filterContext.Exception.Message +
            ". Stack trace: " + filterContext.Exception.StackTrace, 
            filterContext.Exception);
    }
}

Cela fonctionne très bien si une exception non gérée se produit pendant une action du contrôleur.

En ce qui concerne les erreurs 404, j'ai configuré une erreur personnalisée dans mon web.config comme suit :

<customErrors mode="On">
    <error statusCode="404" redirect="~/page-not-found"/>
</customErrors>

Et dans l'action du contrôleur qui gère l'url "page-not-found", j'enregistre l'url originale demandée :

[AcceptVerbs(HttpVerbs.Get)]
public ActionResult PageNotFound()
{
    log.Warn("404 page not found - " + Utils.SafeString(Request.QueryString["aspxerrorpath"]));

    return View();
}

Et cela fonctionne aussi.

Le problème que je rencontre est de savoir comment enregistrer les erreurs qui se trouvent sur les pages .aspx elles-mêmes. Disons que j'ai une erreur de compilation sur l'une des pages ou un code en ligne qui lève une exception :

<% ThisIsNotAValidFunction(); %>
<% throw new Exception("help!"); %>

Il semble que l'attribut HandleError redirige correctement le message vers ma page Error.aspx dans le dossier partagé, mais il n'est absolument pas pris en compte par la méthode OnActionExecuted de mon BaseController. Je pensais que je pourrais peut-être placer le code de journalisation sur la page Error.aspx elle-même, mais je ne sais pas comment récupérer les informations sur les erreurs à ce niveau.

102voto

Andrew Rimmer Points 1887

J'envisagerais de simplifier votre application web en y ajoutant Elmah .

Vous ajoutez l'assemblage Elmah à votre projet, puis vous configurez votre web.config. Il enregistrera alors les exceptions créées au niveau du contrôleur ou de la page. Il peut être configuré pour journaliser à différents endroits (comme le serveur SQL, l'email, etc.). Il fournit également un frontal web, de sorte que vous pouvez parcourir le journal des exceptions.

C'est la première chose que j'ajoute à toute application asp.net mvc que je crée.

J'utilise toujours log4net, mais j'ai tendance à l'utiliser pour la journalisation des débogages/informations, et je laisse toutes les exceptions à Elmah.

Vous pouvez également trouver plus d'informations dans la question Comment enregistrer les erreurs (exceptions) dans vos applications ASP.NET ? .

38voto

Chuck Conway Points 10293

Vous pouvez vous connecter à l'événement OnError dans le fichier Global.asax.

Quelque chose comme ça :

/// <summary>
/// Handles the Error event of the Application control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
protected void Application_Error(object sender, EventArgs e)
{
    if (Server != null)
    {
        Exception ex = Server.GetLastError();

        if (Response.StatusCode != 404 )
        {
            Logging.Error("Caught in Global.asax", ex);
        }

    }

}

21voto

Mark Points 351

MVC3
Créez un attribut qui hérite de l'attribut HandleErrorInfoAttribute et qui inclut votre choix de journalisation.

public class ErrorLoggerAttribute : HandleErrorAttribute 
{
    public override void OnException(ExceptionContext filterContext)
    {
        LogError(filterContext);
        base.OnException(filterContext);
    }

    public void LogError(ExceptionContext filterContext)
    {
       // You could use any logging approach here

        StringBuilder builder = new StringBuilder();
        builder
            .AppendLine("----------")
            .AppendLine(DateTime.Now.ToString())
            .AppendFormat("Source:\t{0}", filterContext.Exception.Source)
            .AppendLine()
            .AppendFormat("Target:\t{0}", filterContext.Exception.TargetSite)
            .AppendLine()
            .AppendFormat("Type:\t{0}", filterContext.Exception.GetType().Name)
            .AppendLine()
            .AppendFormat("Message:\t{0}", filterContext.Exception.Message)
            .AppendLine()
            .AppendFormat("Stack:\t{0}", filterContext.Exception.StackTrace)
            .AppendLine();

        string filePath = filterContext.HttpContext.Server.MapPath("~/App_Data/Error.log");

        using(StreamWriter writer = File.AppendText(filePath))
        {
            writer.Write(builder.ToString());
            writer.Flush();
        }
    }

Placez l'attribut dans Global.asax RegisterGlobalFilters

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

1voto

Kieron Points 10261

Avez-vous pensé à étendre l'attribut HandleError ? Par ailleurs, Scott a publié un bon article sur son blog à propos des intercepteurs de filtres sur les contrôleurs/actions. aquí .

0voto

Mike Chaliy Points 8694

Vous pouvez essayer d'examiner HttpContext.Error, mais je ne suis pas sûr de cela.

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