How to handle exceptions globally in Asp.Net WebApi 2

While developing an Api using ASP.NET WebApi, generally I use ActionFilter to handle unhandled exceptions. To achieve that all we need to do is write a custom ActionFilter extending from ExceptionFilterAttribute as below:


public class GlobalExceptionFilter : ExceptionFilterAttribute
{
    public override void OnException(HttpActionExecutedContext actionExecutedContext)
    {
        var exception = actionExecutedContext.Exception;

        var logger =
            actionExecutedContext.ActionContext.ControllerContext.Configuration.DependencyResolver.GetService(
                typeof (ILogger)) as ILogger;

        if (logger != null)
        {
            logger.Error(exception, exception.Message);
        }

        const string genericErrorMessage = "An unexpected error occured";

        var response = new HttpResponseMessage(HttpStatusCode.InternalServerError)
        {
            Content = new StringContent(genericErrorMessage)
        };

        response.Headers.Add("X-Error", genericErrorMessage);
    }
}

Then register this filter globally as below and call this from application start up code:


public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.Filters.Add(new GlobalExceptionFilter());
    }
}

This will work fine in Asp.Net WebApi 2 also. But problem with this approach is that if any error raised from outside of action then filter will not get chance to handle the error. For example if error raised from following areas then action filter will not able to handle error.

  • Controller constructor
  • Errors inside action filter
  • Exceptions because of routing conflict
  • When Mediatypeformatter failed to negotiate content / Serialization problem
  • Errors inside MessageHandlers

In order to handle errors from those areas one option could be, handle error in HttpApplications Error event.

WebApi 2 offers a very nice alternative way to achieve global exception handling. WebApi2 includes an interface named “IExceptionHandler” and a abstract class “ExceptionHandler”. IExceptionHandler provides extensibility to customize handling of global exceptions. Lets write a custom implementation of ExceptionHandler.


public class GlobalExceptionHandler : ExceptionHandler
{
    public async override Task HandleAsync(ExceptionHandlerContext context, CancellationToken cancellationToken)
    {
        // Access Exception
        // var exception = context.Exception;

        const string genericErrorMessage = "An unexpected error occured";
        var response = context.Request.CreateResponse(HttpStatusCode.InternalServerError, 
            new
            { 
                Message = genericErrorMessage
            });

        response.Headers.Add("X-Error", genericErrorMessage);
        context.Result = new ResponseMessageResult(response);
    }
}

Then Register you exception handler as below from you application startup or owin setup as below:

public static class SetupFiltersExtensions
{
	public static IAppBuilder SetupFilters(this IAppBuilder builder, HttpConfiguration config)
	{
		config.Services.Replace(typeof (IExceptionHandler), new GlobalExceptionHandler());
		
		return builder;
	}
}

Thats it, now you can handle and log all your exceptions. Most probably you noticed that I didn’t log any error in custom exceptionhandler. WebApi2 provides another interface to inject your custom error logger and I prefer to use that one to log my global errors. Sample below:


public class GlobalErrorLogger : ExceptionLogger
{
    public override void Log(ExceptionLoggerContext context)
    {
        var exception = context.Exception;
        // Write your custom logging code here
    }
}

Then you can register our custom logger same way we did before for Custom ExceptionHandler.

public static class SetupFiltersExtensions
{
    public static IAppBuilder SetupFilters(this IAppBuilder builder, HttpConfiguration config)
    {
        config.Services.Replace(typeof (IExceptionHandler), new GlobalExceptionHandler());
        config.Services.Add(typeof(IExceptionLogger), new GlobalErrorLogger());
        
        return builder;
    }
}

You might think why I am using Add instead of Replace, in case of ExceptionLogger. WebApi2 supports multiple Exceptionloggers. That means you can add more than one logger for exception.

Thats all for today. Happy Coding 🙂

Advertisements

5 thoughts on “How to handle exceptions globally in Asp.Net WebApi 2

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s