I use DI in almost all of my applications. Even if you do not use dependency injection, it is very useful for the global exception handler for MVC applications (Web API).
I like @SBirthare's approach, but I would put it in a class that would allow any IoC.
I prefer Autofac, but combining @SBirthare technology with some DIs should give you a centralized place to configure exception handling, but also the ability to log different types of exception handling (if you need it).
This is what I traditionally do:
public abstract class ExceptionHandlerService : IExceptionHandlerService { ILoggingService _loggingSerivce; protected ExceptionHandlerService(ILoggingService loggingService) {
Now you need to register this
builder.RegisterType<ExceptionHandlerService>().As<IExceptionHandlerService();
In an MVC application, you need to implement a class that implements IExceptionFilter
public class CustomHandleError : IExceptionFilter { private readonly IExceptionHandlerService _exceptionHandlerService; public CustomHandleError(IExceptionHandlerService exceptionHandlerService) { _exceptionHandlerService = exceptionHandlerService; } public void OnException(ExceptionContext filterContext) { _exceptionHandlerService.HandleException(filterContext.Exception); } }
To register filters with Autofac
builder.Register(ctx => new CustomHandleError(ctx.Resolve<IExceptionHandlerService>())).AsExceptionFilterFor<BaseController>();
I always define the BaseController from which all my other controllers are. You can define an authorization filter using the same method. Now all controllers are protected and exception handled.
Now you do not need attributes for any classes - the code is in one place.
I don't have a single catch attempt, so we can save the stack trace by the time the exception handler catches the exception.
If you combine this method with @SBirthare -
public abstract class ExceptionHandlerService : IExceptionHandlerService { ILoggingService _loggingSerivce; protected ExceptionHandlerService(ILoggingService loggingService) { //Doing this allows my IoC component to resolve whatever I have //configured to log "stuff" _loggingService = loggingService; } public virtual void HandleException(Exception exception) { //I use elmah a alot - and this can handle WebAPI //or Task.Factory ()=> things where the context is null if (Elmah.ErrorSignal.FromCurrentContext() != null) { Elmah.ErrorSignal.FromCurrentContext().Raise(exception); } else { ErrorLog.GetDefault(null).Log(new Error(exception)); } _loggingService.Log("something happened", exception) //re-direct appropriately var controller = new ErrorController(); var routeData = new RouteData(); var action = "CustomError"; var statusCode = 500; statusCode = exception.GetHttpCode(); switch (exception.GetHttpCode()) { case 400: action = "BadRequest"; break; case 401: action = "Unauthorized"; break; case 403: action = "Forbidden"; break; case 404: action = "PageNotFound"; break; case 500: action = "CustomError"; break; default: action = "CustomError"; break; } //I didn't add the Authentication Error because that should be a separate filter that Autofac resolves. var httpContext = ((MvcApplication)sender).Context; httpContext.ClearError(); httpContext.Response.Clear(); httpContext.Response.StatusCode = statusCode; httpContext.Response.TrySkipIisCustomErrors = true; routeData.Values["controller"] = "Error"; routeData.Values["action"] = action; controller.ViewData.Model = new HandleErrorInfo(ex, currentController, currentAction); ((IController)controller).Execute(new RequestContext(new HttpContextWrapper(httpContext), routeData)); }
}
This gives the same thing, but now you are using dependency injection, and you have the ability to register multiple ExceptionHandlers and allow services based on the type of exception.