LoggingExceptionFilter by Mark Seemann
In a previous post I described how to enable global error handling in ASP.NET MVC applications. Although I spent some time talking about the importance of DRY, another major motivation for me was to enable Dependency Injection (DI) with exception handling so that I could log stack traces before letting ASP.NET MVC handle the exception.
With the ErrorHandlingControllerActionInvoker I described, we can inject any IExceptionFilter implementation. As an example I used HandleErrorAttribute, but obviously that doesn't log anything. Once again, it would be tempting to derive from HandleErrorAttribute and override its OnException method, but staying true to the Single Responsibility Principle as well as the Open/Closed Principle I rather prefer a Decorator:
public class LoggingExceptionFilter : IExceptionFilter { private readonly IExceptionFilter filter; private readonly ILogWriter logWriter; public LoggingExceptionFilter(IExceptionFilter filter, ILogWriter logWriter) { if (filter == null) { throw new ArgumentNullException("filter"); } if (logWriter == null) { throw new ArgumentNullException("logWriter"); } this.filter = filter; this.logWriter = logWriter; } #region IExceptionFilter Members public void OnException(ExceptionContext filterContext) { this.logWriter.WriteError(filterContext.Exception); this.filter.OnException(filterContext); } #endregion }
The LoggingExceptionFilter shown above is unabridged production code. This is all it takes to bridge the gap between IExceptionFilter and some ILogWriter interface (replace with the logging framework of your choice). Notice how it simply logs the error and then passes on exception handling to the decorated IExceptionFilter.
Currently we use HandleErrorAttribute as the decorated filter so that behavior stays as expected.
c.ActionInvoker = new ErrorHandlingControllerActionInvoker( new LoggingExceptionFilter( new HandleErrorAttribute(), logWriter));
This is not too different from before, except that a LoggingExceptionFilter now decorates the HandleErrorAttribute instance.