Registrazione degli errori in ASP.NET MVC


109

Attualmente sto utilizzando log4net nella mia applicazione ASP.NET MVC per registrare le eccezioni. Il modo in cui lo faccio è che tutti i miei controller ereditano da una classe BaseController. Nell'evento OnActionExecuting di BaseController, registro tutte le eccezioni che potrebbero essersi verificate:

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

Funziona alla grande se si verifica un'eccezione non gestita durante un'azione del controller.

Per quanto riguarda gli errori 404, ho un errore personalizzato impostato nel mio web.config in questo modo:

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

E nell'azione del controller che gestisce l'URL "pagina non trovata", registro l'URL originale richiesto:

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

    return View();
}

E funziona anche questo.

Il problema che sto riscontrando è come registrare gli errori che si trovano nelle pagine .aspx stesse. Diciamo che ho un errore di compilazione su una delle pagine o un codice inline che genererà un'eccezione:

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

Sembra che l'attributo HandleError lo stia reindirizzando correttamente alla mia pagina Error.aspx nella cartella condivisa, ma sicuramente non viene rilevato dal metodo OnActionExecuted del mio BaseController. Stavo pensando di poter inserire il codice di registrazione nella pagina Error.aspx stessa, ma non sono sicuro di come recuperare le informazioni sull'errore a quel livello.


+1 per ELMAH. Ecco un tutorial ELMAH che ho scritto per aiutarti a iniziare. Ricordarsi inoltre di utilizzare il pacchetto Elmah.MVC quando si utilizza ASP.NET MVC, per evitare problemi con le pagine di errore personalizzate ecc.
ThomasArdal

Esistono alcuni prodotti che registreranno tutti gli errori che si verificano nelle app .NET. Non sono di basso livello come ELMAH o log4net, ma ti fanno risparmiare un sacco di tempo se stai solo cercando di monitorare e diagnosticare errori: Bugsnag e AirBrake sono due di quelli che so fare .NET
Don P

Risposte:


103

Considererei di semplificare la tua applicazione web collegando Elmah .

Aggiungere l'assembly Elmah al progetto e quindi configurare il file web.config. Quindi registrerà le eccezioni create a livello di controller o di pagina. Può essere configurato per accedere a vari luoghi diversi (come SQL Server, e-mail, ecc.). Fornisce anche un frontend web, in modo da poter navigare nel registro delle eccezioni.

È la prima cosa che aggiungo a qualsiasi app asp.net mvc che creo.

Uso ancora log4net, ma tendo a usarlo per registrare debug / informazioni e lasciare tutte le eccezioni a Elmah.

Puoi anche trovare ulteriori informazioni nella domanda Come si registrano gli errori (eccezioni) nelle app ASP.NET? .


3
Ho iniziato a usare Elmah di recente ed è uno dei logger di eccezioni più intelligenti e semplici che abbia mai usato. Ho letto un post che diceva che MS dovrebbe includerlo in ASP.net e sono d'accordo.
dtc

14
Perché ho bisogno sia di ELMAH che di log4net per l'app. registrazione? Perché non un'unica soluzione?
VJAI

Funzionerà anche se ho un'architettura a più livelli? Controllori - servizi - archivi?
a.farkas2508

2
ELMAH è sopravvalutato.
Ronnie Overby

ELMAH è gratuito?
Dallas

38

Puoi collegarti all'evento OnError in Global.asax.

Qualcosa come questo:

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

    }


}

3
Questo dovrebbe rilevare tutte le eccezioni. Considero questa la migliore pratica.
Andrei Rînea

4
Secondo l'analisi del valore di ReSharper, Serversarà sempre non nullo.
Drew Noakes

6
Ignorare 404 non ha funzionato per me nel modo in cui l'hai scritto. Ho scrittoif (ex is HttpException && ((HttpException)ex).GetHttpCode() == 404) return;
pauloya il

21

MVC3
Crea attributo che eredita da HandleErrorInfoAttribute e include la tua scelta di registrazione

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

Posiziona l'attributo in Global.asax RegisterGlobalFilters

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

1

Hai pensato di estendere l'attributo HandleError? Inoltre, Scott ha un buon post sul blog sugli intercettori dei filtri su controller / azioni qui .


1

La vista Error.aspx è definita in questo modo:

namespace MvcApplication1.Views.Shared
{
    public partial class Error : ViewPage<HandleErrorInfo>
    {
    }
}

HandleErrorInfo ha tre proprietà: stringa ActionName stringa ControllerName Eccezione

Dovresti essere in grado di accedere a HandleErrorInfo e quindi all'eccezione all'interno della visualizzazione.


0

Puoi provare a esaminare HttpContext.Error, ma non ne sono sicuro.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.