Помилки реєстрації в ASP.NET MVC


109

Наразі я використовую log4net в моєму додатку ASP.NET MVC для журналу винятків. Я це роблю, завдяки тому, що всі мої контролери успадковують клас BaseController. У події BaseController OnActionExecuting BaseController я реєструю всі винятки, які могли статися:

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

Це чудово працює, якщо під час дії контролера стався необроблений виняток.

Що стосується 404 помилок, у мене в моїй web.config встановлена ​​спеціальна помилка:

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

І в дії контролера, який обробляє URL-адресу "не знайдено сторінки", я реєструю запит оригінального URL-адреси:

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

    return View();
}

І це теж працює.

Проблема, яка у мене виникає, полягає в тому, як реєструвати помилки, які є на самих сторінках .aspx. Скажімо, у мене є помилка компіляції на одній зі сторінок або якийсь вбудований код, який призведе до виключення:

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

Здається, що атрибут HandleError правильно перенаправляє це на мою сторінку Error.aspx у загальній папці, але він точно не потрапляє методом OnActionExecuted мого BaseController. Я думав, що, можливо, я можу поставити код реєстрації на самій сторінці Error.aspx, але я не впевнений, як отримати інформацію про помилку на цьому рівні.


+1 для ELMAH. Ось підручник ELMAH, який я написав, щоб допомогти вам розпочати роботу. Також не забудьте використовувати пакет Elmah.MVC під час використання ASP.NET MVC, щоб уникнути проблем із користувацькими сторінками помилок тощо
ThomasArdal

Там є кілька продуктів, які будуть реєструвати всі помилки, що виникають у додатках .NET. Вони не настільки низькі, як ELMAH або log4net, але заощаджують багато часу, якщо ви просто намагаєтесь відстежувати та діагностувати помилки: Bugsnag та AirBrake - це два, з яких я знаю. NET
Don P

Відповіді:


103

Я б подумав спростити ваш веб-додаток, підключивши Elmah .

Ви додаєте збірку Elmah до свого проекту, а потім налаштовуєте web.config. Потім буде журнал винятків, створених на рівні контролера або сторінки. Він може бути налаштований для входу в різні місця (наприклад, SQL Server, електронна пошта тощо). Він також надає веб-інтерфейс, щоб ви могли переглядати журнал винятків.

Це перше, що я додаю до будь-якого створеного вами додатку asp.net mvc.

Я все ще використовую log4net, але я схильний використовувати його для реєстрації налагодження / інформації та залишаю всі винятки для Elmah.

Ви також можете знайти додаткову інформацію у питанні Як реєструвати помилки (Винятки) у своїх додатках ASP.NET? .


3
Я нещодавно почав користуватися Elmah, і це один із найкрутіших і найпростіших реєстраторів винятків, які я коли-небудь використовував. Я прочитав пост, в якому говорилося, що MS повинні включити його до ASP.net, і я згоден.
dtc

14
Чому для програми потрібні і ELMAH, і log4net. лісозаготівля? Чому б не єдине рішення?
VJAI

Чи спрацює це, навіть якщо у мене архітектура n-ярусу? Контролери - послуги - сховища?
a.farkas2508

2
ELMAH завищена.
Ронні Овербі

Є ELMAH безкоштовно?
Даллас

38

Ви можете підключитись до події OnError у Global.asax.

Щось на зразок цього:

/// <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
Це має сприймати всі винятки. Я вважаю це найкращою практикою.
Андрій Ронеа

4
Відповідно до аналізу вартості ReSharper, Serverзавжди буде недійсним.
Дрю Ноакс

6
Ігнорування 404 не спрацювало для мене так, як ви це написали. Я писавif (ex is HttpException && ((HttpException)ex).GetHttpCode() == 404) return;
pauloya

21

MVC3
Створити атрибут, який успадковується від HandleErrorInfoAttribute і включає ваш вибір журналу

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

Атрибут місця в Global.asax RegisterGlobalFilters

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

1

Ви думали про розширення атрибуту HandleError? Також у Скотта є хороша публікація в блозі про перехоплювачі фільтрів на контролерах / діях тут .


1

Погляд Error.aspx визначається так:

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

HandleErrorInfo має три властивості: рядок ActionName рядок ControllerName Exception Exception

Ви повинні мати доступ до HandleErrorInfo і, отже, Виняток у представленні.


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.