Logging errors in ASP.NET MVC
我目前正在ASP.NET MVC应用程序中使用log4net来记录异常。我这样做的方法是让我的所有控制器继承自BaseController类。在BaseController的OnActionExecuting事件中,我记录可能发生的任何异常:
1 2 3 4 5 6 7 8 9 10 11 12 | 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中设置了自定义错误,如下所示:
1 2 3 | <customErrors mode="On"> <error statusCode="404" redirect="~/page-not-found"/> </customErrors> |
在处理"页面未找到"网址的控制器操作中,我记录了所请求的原始网址:
1 2 3 4 5 6 7 | [AcceptVerbs(HttpVerbs.Get)] public ActionResult PageNotFound() { log.Warn("404 page not found -" + Utils.SafeString(Request.QueryString["aspxerrorpath"])); return View(); } |
这也有效。
我遇到的问题是如何记录.aspx页面本身的错误。假设我在其中一个页面或某些内联代码上出现编译错误,这将导致异常:
1 2 | <% ThisIsNotAValidFunction(); %> <% throw new Exception("help!"); %> |
似乎HandleError属性正确地将其重新路由到Shared文件夹中的Error.aspx页面,但它肯定没有被我的BaseController的OnActionExecuted方法捕获。我想我可以将日志代码放在Error.aspx页面本身,但我不确定如何在该级别检索错误信息。
我会考虑通过插入Elmah来简化您的Web应用程序。
您将Elmah程序集添加到项目中,然后配置web.config。然后,它将记录在控制器或页面级别创建的异常。它可以配置为记录到各种不同的位置(如SQL Server,电子邮件等)。它还提供了Web前端,以便您可以浏览异常日志。
它是我添加到我创建的任何asp.net mvc应用程序的第一件事。
我仍然使用log4net,但我倾向于使用它来记录调试/信息,并将所有例外留给Elmah。
您还可以在问题中找到更多信息如何在ASP.NET应用程序中记录错误(例外)?
您可以挂钩Global.asax中的OnError事件。
像这样的东西:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /// <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,并包括您选择的日志记录
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | 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中
1 2 3 4 5 | public static void RegisterGlobalFilters(GlobalFilterCollection filters) { // filters.Add(new HandleErrorAttribute()); filters.Add(new ErrorLoggerAttribute()); } |
Error.aspx视图定义如下:
1 2 3 4 5 6 | namespace MvcApplication1.Views.Shared { public partial class Error : ViewPage<HandleErrorInfo> { } } |
HandleErrorInfo有三个属性:
字符串ActionName
字符串ControllerName
例外例外
您应该能够访问HandleErrorInfo,从而访问视图中的Exception。
您是否考虑过扩展HandleError属性?此外,斯科特有一篇关于控制器/动作的过滤器拦截器的博客文章。
您可以尝试检查HttpContext.Error,但我不