ASP.NET MVC中的记录错误


109

我当前在ASP.NET MVC应用程序中使用log4net记录异常。我这样做的方法是让我所有的控制器都继承自BaseController类。在BaseController的OnActionExecuting事件中,我记录了可能发生的所有异常:

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属性可以正确地将此路由重新路由到Shared文件夹中的Error.aspx页面,但绝对不会被BaseController的OnActionExecuted方法捕获。我本以为可以将日志记录代码放在Error.aspx页面本身上,但是我不确定如何在该级别上检索错误信息。


+1为ELMAH。这是我编写的ELMAH教程,可以帮助您入门。还记得使用ASP.NET MVC时要使用Elmah.MVC软件包,以避免自定义错误页面等问题
。– ThomasArdal

有一些产品可以记录.NET应用程序中发生的所有错误。他们不是为低级别ELMAH或log4net的,但为您节省大量的时间,如果你只是想监视和诊断错误:Bugsnag减速板是两个,我知道做.NET
唐P

Answers:


103

我会考虑通过插入Elmah来简化您的Web应用程序

您将Elmah程序集添加到项目中,然后配置web.config。然后它将记录在控制器或页面级别创建的异常。可以将其配置为登录到各种不同的位置(例如SQL Server,电子邮件等)。它还提供了一个Web前端,以便您可以浏览异常日志。

这是我添加到我创建的任何asp.net mvc应用程序中的第一件事。

我仍然使用log4net,但是我倾向于使用它来记录调试/信息,并将所有异常留给Elmah。

您还可以在如何在ASP.NET应用程序中记录错误(异常)问题中找到更多信息


3
我最近开始使用Elmah,它是我使用过的最流畅,最简单的异常记录器之一。我读了一篇帖子,说MS应该将其包含在ASP.net中,我同意。
dtc

14
为什么我需要ELMAH和log4net作为应用程序。记录?为什么没有一个解决方案?
VJAI 2012年

即使我具有n层体系结构,这也可以工作吗?控制器-服务-信息库?
a.farkas2508 2015年

2
ELMAH被高估了。
罗尼·奥弗比

ELMAH是免费的吗?
达拉斯

38

您可以在Global.asax中加入OnError事件。

像这样:

/// <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
这应该捕获所有异常。我认为这是最佳做法。
AndreiRînea2010年

4
根据ReSharper的价值分析,Server将始终为非null。
Drew Noakes

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中的Place属性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

您应该能够访问HandleErrorInfo并因此可以访问视图中的Exception。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.