【问题标题】:ASP.Net MVC Exception Logging combined with Error HandlingASP.Net MVC 异常记录结合错误处理
【发布时间】:2010-11-05 03:58:30
【问题描述】:

我正在寻找一个简单的解决方案来在我的 ASP.Net MVC 1.0 应用程序中执行异常日志记录和错误处理。

我已经阅读了很多文章,包括 StackOverflow 上发布的问题,它们都针对不同的情况提供了不同的解决方案。我仍然无法提出适合我需要的解决方案。

这是我的要求:

  1. 为了能够在我的控制器上使用 [HandleError] 属性(或等效的),来处理可能从任何操作或视图抛出的所有异常。这应该处理所有未在任何操作上专门处理的异常(如第 2 点所述)。我希望能够为控制器中的所有操作指定在错误情况下必须将用户重定向到哪个视图。

  2. 我希望能够在特定操作的顶部指定 [HandleError] 属性(或等效项)以捕获特定异常并将用户重定向到适合该异常的视图。所有其他异常仍必须由 Controller 上的 [HandleError] 属性处理。

  3. 在上述两种情况下,我都希望使用 log4net(或任何其他日志库)记录异常。

我该如何实现上述目标?我已经阅读了有关让我的所有控制器都从覆盖 OnException 方法的基本控制器继承的信息,并在其中进行日志记录。但是,这会将用户重定向到适当的视图,或者让它变得混乱。

我已经阅读了有关编写自己的过滤器操作的信息,该操作实现了 IExceptionFilter 来处理此问题,但这会与 [HandleError] 属性冲突。

到目前为止,我的想法是最好的解决方案是编写我自己的继承自 HandleErrorAttribute 的属性。这样我就可以获得 [HandleError] 的所有功能,并且可以添加我自己的 log4net 日志记录。解决方法如下:

    public class HandleErrorsAttribute: HandleErrorAttribute {

      private log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

      public override void OnException(ExceptionContext filterContext)
      {
          if (filterContext.Exception != null)
          {
            log.Error("Error in Controller", filterContext.Exception);
          }

          base.OnException(filterContext);
      }
   }

上面的代码能满足我的要求吗?如果不是,什么解决方案可以满足我的要求?

【问题讨论】:

    标签: asp.net-mvc logging exception-handling log4net


    【解决方案1】:

    我仍然对所有不同的解决方案以及属性如何相互干扰感到有些困惑,但我选择了这个解决方案:

    public class LogErrorsAttribute: FilterAttribute, IExceptionFilter
    {
        #region IExceptionFilter Members
    
        void IExceptionFilter.OnException(ExceptionContext filterContext)
        {
            if (filterContext != null && filterContext.Exception != null)
            {
                string controller = filterContext.RouteData.Values["controller"].ToString();
                string action = filterContext.RouteData.Values["action"].ToString();
                string loggerName = string.Format("{0}Controller.{1}", controller, action);
    
                log4net.LogManager.GetLogger(loggerName).Error(string.Empty, filterContext.Exception);
            }
    
        }
    
        #endregion
    }
    

    我仍然使用原始问题中解释的 [HandleError] 属性,我只是用 [LogErrors] 属性装饰每个控制器。

    这对我有用,因为它将错误日志记录在一个地方,并且不会导致多次记录重复的异常(如果我扩展 [HandleError] 并在多个地方使用该属性就会发生这种情况)。

    我认为不可能将异常记录和错误处理合并到一个属性或类中,否则会变得非常繁琐和复杂,或者不影响 [HandleError] 的使用

    但这对我有用,因为我只使用 [LogErrors] 属性装饰每个控制器一次,并使用 [HandleError] 完全按照我想要的方式装饰控制器和操作,而不会相互干扰。

    更新:

    这是我如何使用它的示例:

    [LogErrors(Order = 0)]
    [HandleError(Order = 99)]
    public class ContactController : Controller
    {
        public ActionResult Index()
        {
            return View(Views.Index);
        }
    
        public ActionResult Directions()
        {
            return View(Views.Directions);
        }
    
    
        public ActionResult ContactForm()
        {
            FormContactMessage formContactMessage = new FormContactMessage();
    
            return View(Views.ContactForm,formContactMessage);
        }
    
        [HandleError(ExceptionType = typeof(SmtpException), View = "MessageFailed", Order = 1)]
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult ContactForm(FormContactMessage formContactMessage)
        {
            if (ModelState.IsValid)
            {
                if (formContactMessage.IsValid)
                {
                    SmtpClient client = new SmtpClient();
    
                    MailAddress recipientAddress = new MailAddress(Properties.Settings.Default.ContactFormRecipientEmailAddress);
                    MailAddress senderAddress = new MailAddress(Properties.Settings.Default.ContactFormSenderEmailAddress);
                    MailMessage mailMessage = formContactMessage.ToMailMessage(recipientAddress, senderAddress);
    
                    client.Send(mailMessage);
    
                    return View("MessageSent");
                }
                else
                {
                    ModelState.AddRuleViolations(formContactMessage.GetRuleViolations());
                }
            }
            return View(Views.ContactForm, formContactMessage);
        }
    
        private static class Views
        {
            public static string Index { get { return "Index"; } }
            public static string Directions { get { return "Directions"; } }
            public static string ContactForm { get { return "ContactForm"; } }
    
        }
    }
    

    在上面的代码中,ContactForm 动作重载中的 SmtpExceptions 以一种非常具体的方式处理 - 向用户呈现一个特定于发送失败消息的 ViewPage,在本例中称为“MessageFailed”。所有其他异常都由 [HandleError] 的默认行为处理。另请注意,首先记录错误,然后处理错误。如下所示:

    [LogErrors(Order = 0)]
    [HandleError(Order = 99)]
    

    更新:

    有一个替代解决方案,有一个很好的解释。我建议通读一遍以更好地理解所涉及的问题。

    ASP.NET MVC HandleError Attribute, Custom Error Pages and Logging Exceptions (感谢下面的 Scott Shepherd,他在下面的答案中提供了链接)。

    【讨论】:

    • 我怀疑这段代码有一个错误,它假设 RouteData.Values["action"] 没有返回 null - 对其调用 .ToString() 可能会导致您的错误处理程序抛出 NullReferenceException。没有什么比错误处理程序抛出错误更令人沮丧的了。
    猜你喜欢
    • 1970-01-01
    • 2011-06-03
    • 2010-11-10
    • 2010-10-23
    • 1970-01-01
    • 2021-03-31
    • 2012-02-10
    • 2012-02-02
    • 2016-12-31
    相关资源
    最近更新 更多