Global Exception Handling in ASP.NET Core WEB API

Datetime:2016-08-22 22:06:47          Topic: ASP.NET           Share

Exception handling is one of the most important part of any application that needs to addressed and implemented properly. With respect to ASP.NET Core , things have changed and are in better shape to implement exception handling. Implementing exception handling for every action method in API, is quite time consuming and requires extra efforts. So in this post, find out how to implement global exception handling in ASP.NET Core WEB API .

The benefit of implementing global exception handling is that you need to implement in at one place. Any exception occurs in your application will be handled, even when you add new controllers or new methods. That’s quite cool. Isn’t it? Now, let’s see how to implement it.

Global Exception Handling in ASP.NET Core WEB API

There are a couple of ways to implement exception handling globally. You might be aware about introduction of Middlware in ASP.NET Core and ASP.NET Core is shipped with the some in-built middleware components. And one of the in-bulit ASP.NET Core diagnostic middleware is UseExceptionHandler . Read more about Various ASP.NET Core Diagnostics Middleware

UseExceptionHandler can be used to handle exceptions globally. You can get all the details of exception object like Stack Trace, Inner exception and others. And then you can show them on screen. You can easily implement like this.

app.UseExceptionHandler(
 options => {
    options.Run(
    async context =>
    {
      context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
      context.Response.ContentType = "text/html";
      var ex = context.Features.Get<IExceptionHandlerFeature>();
      if (ex != null)
      {
        var err = $"<h1>Error: {ex.Error.Message}</h1>{ex.Error.StackTrace }";
        await context.Response.WriteAsync(err).ConfigureAwait(false);
      }
    });
 }
);

You need to put this inside configure() of startup.cs file. Now let’s throw some exception. I am using the default template of ASP.NET Core Web API project. So open ValuesController.cs , modify the Get() method to throw an exception.

// GET api/values
[HttpGet]
public IEnumerable<string> Get()
{
    string[] arrRetValues = null;
    if(arrRetValues.Length > 0)
    { }
    return arrRetValues;
}

Run the application and you should see following. You can also debug it and check in case of exception, it is hitting the app.UseExceptionHandler() code.

This is simple and all good. Another way to implement it using IExceptionFilter and by creating your own custom exception handler. The interface looks like,

namespace Microsoft.AspNetCore.Mvc.Filters
{
    public interface IExceptionFilter : IFilterMetadata
    {
        void OnException(ExceptionContext context);
    }
}

As you can see, there is only one method which needs to be implemented. And this method will be invoked whenever there is an unhandled exception. So let’s create a class which implements IExceptionFilter .

public class CustomExceptionFilter : IExceptionFilter
{
    public void OnException(ExceptionContext context)
    {
        HttpStatusCode status = HttpStatusCode.InternalServerError;
        String message = String.Empty;

        var exceptionType = context.Exception.GetType();
        if (exceptionType == typeof(UnauthorizedAccessException))
        {
            message = "Unauthorized Access";
            status = HttpStatusCode.Unauthorized;
        }
        else if (exceptionType == typeof(NotImplementedException))
        {
            message = "A server error occurred.";
            status = HttpStatusCode.NotImplemented;
        }
        else if (exceptionType == typeof(MyAppException))
        {
            message = context.Exception.ToString();
            status = HttpStatusCode.InternalServerError;
        }
        else
        {
            message = context.Exception.Message;
            status = HttpStatusCode.NotFound;
        }
        HttpResponse response = context.HttpContext.Response;
        response.StatusCode = (int)status;
        response.ContentType = "application/json";
        var err = message + " " + context.Exception.StackTrace;
        response.WriteAsync(err);
    }
}

Here exception type is checked and based on exception type, message and status properties are set. There is also a custom exception type MyAppException (line no. 19) used. To create custom exception, class needs to be inherited from Exception class.

public class MyAppException : Exception
{
    public MyAppException()
    { }

    public MyAppException(string message)
        : base(message)
    { }

    public MyAppException(string message, Exception innerException)
        : base(message, innerException)
    { }
}

And finally add our filter using the ConfigureServices method in the Startup class.

public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddApplicationInsightsTelemetry(Configuration);
    services.AddMvc(
        config => { 
            config.Filters.Add(typeof(CustomExceptionFilter));
        }
    );
}

Now when you run the application and exception occurs, then it will be handled by onException method. And to test custom exception, update Get(int id) method to throw custom exception.

// GET api/values/5
[HttpGet("{id}")]
public string Get(int id)
{
    string sMessage = "test";
    if (sMessage.Length > 0)
    {
        throw new MyAppException("My Custom Exception");
    }
    return sMessage;
}

Summary

So in this post, we learnt about handling exception globally either via built-in middleware or using the built-in exception filter.

Thank you for reading. Keep visiting this blog and share this in your network. Please put your thoughts and feedback in comments section.





About List