2009-02-20 16 views
97

Aktualnie używam log4net w mojej aplikacji ASP.NET MVC do rejestrowania wyjątków. Sposób, w jaki to robię, polega na tym, że wszystkie moje kontrolery dziedziczą z klasy BaseController. W przypadku, gdy BaseController za OnActionExecuting, loguję żadnych wyjątków, które mogły wystąpić:Błędy rejestrowania w środowisku ASP.NET MVC

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

Działa to doskonale, jeśli Wystąpił nieobsługiwany wyjątek podczas działania kontrolera.

chodzi o 404 błędów, mam błąd niestandardowy zestaw w moim web.config tak:

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

A w akcji kontrolera, który zajmuje się "page-not-found" url, I logowaniu wymagany oryginalny adres URL:

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

    return View(); 
} 

To też działa.

Problem, który mam, to sposób rejestrowania błędów znajdujących się na stronach .aspx. Powiedzmy, że mam błąd kompilacji na jednej ze stron lub jakimś kodem inline że rzuci wyjątek:

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

Wydaje się, że atrybut HandleError jest poprawnie przekierowanie to na mojej stronie Error.aspx w folderze udostępnionym ale zdecydowanie nie jest przechwycony przez moją metodę OnActionExecuted BaseController. Pomyślałem, że mógłbym umieścić kod logowania na samej stronie Error.aspx, ale nie jestem pewien, jak odzyskać informacje o błędzie na tym poziomie.

+0

+1 dla ELMAH. Oto samouczek [ELMAH] (http://blog.elmah.io/elmah-tutorial/), który napisałem, aby pomóc Ci zacząć. Pamiętaj także o używaniu pakietu [Elmah.MVC] (https://www.nuget.org/packages/Elmah.MVC/) podczas korzystania z ASP.NET MVC, aby uniknąć problemów z niestandardowymi stronami błędu itp. – ThomasArdal

+0

Jest kilka produktów tam, które będzie rejestrować wszystkie błędy występujące w aplikacjach .NET. Nie są tak niskiego poziomu, jak ELMAH czy log4net, ale oszczędzają mnóstwo czasu, jeśli próbujesz monitorować i diagnozować błędy: [Bugsnag] (https://docs.bugsnag.com/platforms/dotnet/ asp-net /) i [AirBrake] (https://airbrake.io/languages/net_bug_tracker) to dwa z tych, które znam .NET –

Odpowiedz

96

Chciałbym rozważyć uproszczenie Twojej aplikacji internetowej poprzez podłączenie Elmah.

Dodaj zespół Elmah do projektu, a następnie skonfiguruj plik web.config. Następnie będzie rejestrować wyjątki utworzone na poziomie kontrolera lub strony. Można go skonfigurować do logowania do różnych miejsc (takich jak serwer SQL, poczta e-mail itp.). Zapewnia także interfejs WWW, dzięki czemu można przeglądać dziennik wyjątków.

Jest to pierwsza rzecz, którą dodaję do dowolnej aplikacji mvc asp.net, którą tworzę.

Nadal używam log4net, ale używam go do rejestrowania debugowania/informacji i zostawiam wszystkie wyjątki dla Elmah.

Możesz również znaleźć więcej informacji w pytaniu How do you log errors (Exceptions) in your ASP.NET apps?.

+3

Niedawno zacząłem używać Elmah i jest to jeden z najłagodniejszych i najprostszych rejestratorów wyjątków, jakie mam. kiedykolwiek użyte. Przeczytałem post mówiąc, że MS powinien zawrzeć to w ASP.net i zgadzam się. – dtc

+13

Dlaczego potrzebuję zarówno ELMAH, jak i log4net dla aplikacji. wycięcie lasu? Dlaczego nie jedno rozwiązanie? – VJAI

+0

Czy to działa, nawet jeśli mam architekturę n-warstwową? Kontrolery - usługi - repozytoria? –

1

Możesz spróbować zbadać HttpContext.Error, ale nie jestem tego pewien.

2

Czy zastanawiałeś się nad rozszerzeniem atrybutu HandleError? Scott ma również dobry wpis na blogu o filtrach przechwytujących na kontrolerach/akcjach here.

1

Widok Error.aspx jest zdefiniowany następująco:

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

HandleErrorInfo ma trzy właściwości: ciąg ActionName ciąg ControllerName Wyjątek Wyjątek

Powinieneś być w stanie uzyskać dostęp HandleErrorInfo i dlatego Wyjątek w widoku.

35

Możesz podłączyć się do zdarzenia OnError w pliku Global.asax.

coś takiego:

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

    } 


} 
+2

To powinno wychwycić wszystkie wyjątki. Uważam to za najlepszą praktykę. –

+4

Zgodnie z analizą wartości ReSharper, 'Server' zawsze ma wartość inną niż null. –

+6

Ignorowanie 404 nie działa dla mnie tak, jak to napisałeś. Napisałem 'if (ex jest HttpException && ((HttpException) ex) .GetHttpCode() == 404) return;' – pauloya

19

MVC3
Utwórz atrybut, który dziedziczy HandleErrorInfoAttribute i obejmuje wybór rejestrowania

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

atrybutu miejsce w global.asax RegisterGlobalFilters

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