Logging errors in ASP.NET MVC

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

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

This works great if an unhandled exception occurred during a controller action.

至于404错误,我在 web.config 中设置了一个自定义错误,如下所示:

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

在处理“ page-not-found”url 的控制器操作中,我记录被请求的原始 url:

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


return View();
}

And this also works.

我遇到的问题是如何记录。Aspx 页面本身。假设某个页面出现编译错误,或者某个内联代码抛出异常:

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

看起来 HandleError 属性正在将其重新路由到我的共享文件夹中的 Error.aspx 页面,但是它肯定没有被 BaseController 的 OnActionExecated 方法捕获。我想也许我可以把日志代码放在 Error.aspx 页面上,但是我不确定如何在那个级别检索错误信息。

93323 次浏览

您可以尝试检查 HttpContext.Error,但我对此不确定。

您是否考虑过扩展 HandleError 属性?此外,Scott 还有一篇关于控制器/操作 here上的过滤拦截器的博文。

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

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

这是我创建的第一个 asp.net mvc 应用程序。

我仍然使用 log4net,但是我倾向于用它来记录调试/信息,并且把所有的例外留给 Elmah。

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

Aspx 视图的定义如下:

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

HandleErrorInfo 有三个属性: 字符串 ActionName 字符串 ControllerName 例外

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

可以挂接到 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);
}


}




}

MVC3
创建从 HandleErrorInfoAttribute 继承的 Attribute,并包括您选择的日志记录

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

Place attribute in Global.asax RegisterGlobalFilters

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