ASP.NET Core 8: Improved exception handling with IExceptionHandler
Introduction
ASP.NET Core 8 is coming soon and bring great improvements! In this post I will show how Exception handling is improved with the new interface IExceptionhandler.
No more middleware to handle exceptions!
The great news is you no longer need to handle global exceptions in a middleware since ASP.NET Core brought middleware. To remind you what’s a middleware and how you can handle Exception with, you can read my previous post on exception handling here: https://anthonygiretti.com/2018/11/18/common-features-in-asp-net-core-2-1-webapi-error-handling/.
With ASP.NET Core 8 you can design a class that implements the IExceptionhandler interface. The latter describe the following contract:
public interface IExceptionHandler
{
ValueTask<bool> TryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken);
}
You can implement the logic you want and return the response you desire to the client. important thing. You must return True or False. If you return True, the pipeline execution will end and other middlewares in the pipeline won’t be invoked. If you return False, the pipeline will continue its execution. Let’s see a example of an implementation:
In this class (which supports Dependency Injection) you can add logging and return a response with the WriteAsJsonAsync which takes in parameter a ProblemDetails instance. You can add anything in the response, I chose ProblemDetails because it’s a RFC standard to handle errors returned on HTTP APIs responses. You can find the RFC here: https://datatracker.ietf.org/doc/html/rfc7807.
Note that the default HTTP Status code return is 500, you customize it as follow if you need:
httpContext.Response.StatusCode = (int)HttpStatusCode.RequestTimeout;
To register your Exception handler, proceed as follow:
Use the method named AddException<T>() to register your handler, and use the method named UseExceptionHandler() which needs options paramters (that can remain empty) to work. If you run the app with invoke the /exception in my sample you will get following response:
Chaining Exception handlers
A great thing is that you can you chain exception handlers. How? By returning False, the pipeline will pursue its execution and invoke the next Exception handler. If every Exception handlers return False, the pipeline will execute all middlewares that remains in the pipeline. You can definitely combine Exception handlers and middlewares if you were wondering if it’s possible.
To chain your Exception handlers and only want to handle exception with them, chain them, but you HAVE TO define a default Exception handler that will run (and placed in the last position) to handle any Exception that has been handled by the previous handlers. The order matters! The following example shows an Exception handler that handles (only) TimeOutException and breaks the pipeline execution if the Exception is effectively a TimeOutException. If not the pipeline execution will continue and reach the default Exception handler as follow:
If you try now to invoke the /timeout endpoint the right response will be sent to the client and the default Exception handler won’t be invoked:
If you try to invoke again the /exception endpoint, the pipeline will still reach first the TimeOutException handler but the latter won’t manage the response since it’s not a TimeOutException and will return False in order to tell the pipeline to pursue its exception and reach the default Exception handler.
Hope, like me, you will enjoy this new feature 🙂