ASP.Net MVC Exception Logging combined with Error Handling
我正在寻找一个简单的解决方案,在我的ASP.Net MVC 1.0应用程序中结合错误处理进行异常记录。
我已经阅读了很多文章,包括StackOverflow上发布的问题,这些文章都针对不同情况提供了不同的解决方案。我仍然无法提出适合我需求的解决方案。
这是我的要求:
为了能够在我的Controller上使用[HandleError]属性(或类似的东西),处理可能从任何Actions或Views中抛出的所有异常。这应该处理所有未在任何操作上专门处理的异常(如第2点所述)。对于Controller中的所有操作,我希望能够指定在错误情况下必须将用户重定向到哪个View。
我希望能够在特定Actions的顶部指定[HandleError]属性(或等效的东西)以捕获特定异常并将用户重定向到适合该异常的View。所有其他异常仍必须由Controller上的[HandleError]属性处理。
在上述两种情况下,我都希望使用log4net(或任何其他日志记录库)记录异常。
我如何实现上述目标?我已经阅读过让我的所有控制器继承自一个覆盖OnException方法的基本控制器,并且我在其中进行日志记录。但是,这会将用户重定向到适当的视图,或者使其变得混乱。
我已经阅读过编写自己的Filter Action来实现IExceptionFilter来处理这个问题,但这会与[HandleError]属性冲突。
到目前为止,我的想法是,最好的解决方案是编写自己继承自HandleErrorAttribute的属性。这样我就可以获得[HandleError]的所有功能,并且可以添加我自己的log4net日志记录。解决方案如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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); } } |
以上代码是否适用于我的要求?如果没有,哪种解决方案能满足我的要求?
我仍然对所有不同的解决方案感到困惑,以及属性如何相互干扰,但我选择了这个解决方案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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]装饰控制器和动作完全按照我想要的方式,而不会相互干扰。
更新:
以下是我如何使用它的示例:
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 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | [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"; } } } } |
在上面的代码中,
1 2 | [LogErrors(Order = 0)] [HandleError(Order = 99)] |
更新:
有一个替代解决方案,具有非常好的解释。我建议通读它以更好地理解所涉及的问题。
ASP.NET MVC HandleError属性,自定义错误页面和日志记录异常
(感谢下面的Scott Shepherd,他在下面的答案中提供了链接)。