MVC [HandleError] HandleErrorAttribute called twice when using global logging
在我使用的MVC3 Web应用程序中
1 2 3 4 | public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new HandleErrorAttribute()); } |
应用全局错误处理,如果发生未处理的异常,则向用户显示"错误"视图。
对于一个特定的视图,如果通过使用
然后我想添加未处理异常的全局日志记录。我创建了一个带有日志代码的自定义HandleError属性:
1 2 3 4 5 6 7 8 | public class MyHandleErrorAttribute : HandleErrorAttribute { public override void OnException(ExceptionContext context) { // Write to log code base.OnException(context); } } |
并更新了RegisterGlobalFilters和方法修饰以改为使用此属性名称。这通常有效,但是当用
最终,我想记录所有未处理的异常(一次),同时保留[HandleError]提供的功能,特别是为特定方法异常设置不同的视图。这样做有干净的方法吗?
我相信我自己找到了一个干净的解决方案。扩展HandleError似乎是一个好主意,但现在我认为这是朝着错误方向迈出的一步。我不想以不同的方式处理任何错误,只需在HandleError选择它们之前将异常写入一次。因此,默认的HandleError可以按原样保留。虽然可以多次调用OnException,但在HandleErrorAttribute的标准实现中它似乎完全是良性的。
相反,我创建了一个异常日志过滤器
1 2 3 4 5 6 7 | public class LoggedExceptionFilter : IExceptionFilter { public void OnException(ExceptionContext filterContext) { // logging code } } |
它不需要从
1 2 3 4 5 | public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new LoggedExceptionFilter()); filters.Add(new HandleErrorAttribute()); } |
这样可以在不更改标准
试试这个,
1 2 3 4 5 6 7 8 9 10 11 12 | public class MyHandleErrorAttribute : HandleErrorAttribute { public override void OnException(ExceptionContext context) { var exceptionHandled = context.ExceptionHandled; base.OnException(context); if(!exceptionHandled && context.ExceptionHandled) // log the error. } } |
您可以创建一个自定义
1 2 3 4 5 6 7 8 9 10 | public class MyFilterProvider : IFilterProvider { public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor) { if (!actionDescriptor.GetFilterAttributes(true).Any(a => a.GetType() == typeof(MyHandleErrorAttribute))) { yield return new Filter(new MyHandleErrorAttribute(), FilterScope.Global, null); } } } |
然后,您将在
1 | FilterProviders.Providers.Add(new MyFilterProvider()); |
或者(类似于@Mark提出的)你可以显式设置
1 2 3 4 5 6 7 8 9 10 11 | public class MyHandleErrorAttribute : HandleErrorAttribute { public override void OnException(ExceptionContext context) { if(context.ExceptionHandled) return; // Write to log code base.OnException(context); context.ExceptionHandled = true; } } |
我实际上找到了保持OnException方法不会触发两次的解决方案。如果您正在使用FilterConfig.RegisterGlobalFilters()方法,请注释掉HandleErrorAttribute的注册:
1 2 3 4 5 6 7 | public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { //filters.Add(new HandleErrorAttribute()); } } |
实际上,我还使用了内置的HandleErrorAttribute而没有注册它,并且它工作正常。我只需要打开自定义错误:
1 2 3 | <system.web> <customErrors mode="On" /> </system.web> |