ASP.NET Core Exception Middleware
Microsoft documentation defines ASP.NET Core middleware as “software that’s assembled into an app pipeline to handle requests and responses”. The way I like to think about it — it’s a piece of logic that executes on every request.
Introduction
In this specific story, we will look at how to setup an Exception
middleware in your ASP.NET Web API. The end goal is to have one place to catch all your Exceptions
and write the API response back.
The reason why this is very powerful is because you define a single place to handle all of your Exception
logic and you only have one snippet of try {} catch {}
code.
Exceptions and responses
Let’s take a look at how we can define custom Exceptions
and a custom response for the middleware. You, of course, don’t have to do this part and can skip to the Middleware section.
Exceptions
I like using at least 2 different Exception
classes. One is an abstract
one that essentially defines the schema and the other is a friendly one that I can throw anywhere in the code — additionally, I have one for NotFound (404)
, but that is out of scope for this story.
Responses
I define a specific class to return in the middleware response. This is helpful as it lets you customize the StatusCode
and Message
. This is based on ASP.NET’s built in ProblemDetails object.
As you might’ve already guessed — the StatusCode
in the Exception
maps to the Code
in the AuthProblemDetail
response object and — the Message
in the Exception
maps to the Message
in the AuthProblemDetail
response object.
Middleware
Now let’s take a look at creating the actual middleware. This specific one will consist of 2 main parts — delegate call and a function to write the response.
As you can see, the try {} catch {}
code is wrapped around the await _next(httpContext)
call. This will be the only place you will have that snippet and it ensures that it runs on every request. It is also a catch-all for all Exceptions
.
There are a few things that happen once the Exception
is caught.
- (Line 33) Determine the
id
. This is used to log theException
error and write in the response so an end-user can provide it back to a develop and they can easily find the error in the logs. - (Line 37) Log the
Exception
error with theid
. - (Line 41) Call
WriteExceptionResponseAsync()
function to write the response back.
Inside the WriteExceptionResponseAsync()
function, I create the AuthProblemDetail
object with the Message
, StatusCode
and TraceId
from the parameters.
Afterwards, check if the Exception
thrown is an AuthException
. If so, then replace the StatusCode
, Message
with the AuthException
status code and message.
Finally, just update the httpContext
status code, content type and write the response back.
That’s it! This is all you need to create an Exception
middleware! Now, you can throw an Exception
anywhere in your code and this will pick it up. For example, if a user’s password doesn’t match, then throw a BadRequest (400) Exception
. The message will be returned to the user and the status code will be 400
.
Final details
Source code where these examples were take from
Source code jump to