Creating Exception Middleware
In this lesson, we're going to create exception middleware to handle internal server error
Get the project source code below, and follow along with the lesson material.
Download Project Source CodeTo set up the project on your local machine, please follow the directions provided in the README.md
file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.
This lesson preview is part of the The newline Guide to Fullstack ASP.NET Core and React course and can be unlocked immediately with a single-time purchase. Already have access to this course? Log in here.
Get unlimited access to The newline Guide to Fullstack ASP.NET Core and React with a single-time purchase.

[00:00 - 00:21] We have made our not found error, bad request error, and unknown endpoint error consistent. Now we have to work on making our internal server error consistent as well, which looks like this right now.
[00:22 - 00:35] In production this error doesn't mean anything, but in development we still want to show this stack trace as it contains some useful information for the developer. We can start working on it right now.
[00:36 - 00:45] Let's go back to our project. Right now we do have an API response class, which is responsible for sending the status code and the error message.
[00:46 - 00:56] But for this particular error, we need to add the error details as well. So what we can do is we can extend it to include the details field to our response.
[00:57 - 01:15] What we'll do is create a new class inside error response and we will call it API exception. And we will derive from the API response.
[01:16 - 01:31] We will create a constructor, which already has a status code and an error message. To include the error details here, we need to create a new property, which will be a string and will be called details.
[01:32 - 01:50] So it will be string and we will simply call it details. And we can add it to our constructor and make the default value to be null here as well.
[01:51 - 02:07] And inside, we will make details equal to the details provided inside the constructor. Now that we have created an exception class, we need to create a middleware, which will be responsible to show this particular exception.
[02:08 - 02:32] So inside the API project, let's create a new folder and we will call it middle ware. And inside, we will create a new class and we'll call it exception middleware.
[02:33 - 02:54] We will create a constructor and first of all, we will inject request delegate request, delegate, let's call it next. We want I logger and it will take a type.
[02:55 - 03:05] So let's call it exception middleware and we will simply call it logger. And we also want our environment details.
[03:06 - 03:23] So we can use I host environment and we will call it ENV. Let's import request delegate from netcode.http we will import.
[03:24 - 03:38] I logger from Microsoft extensions dot logging and host environment using Microsoft extensions dot hosting. We will now initialize the fields from parameter.
[03:39 - 03:53] So let's do it one by one for next, for logger, for ENV. We will create a public method.
[03:54 - 04:03] So I will write public async. We can call it invoke async.
[04:04 - 04:12] Let's import task from threading dot tasks. As a parameter, it will take HTTP context.
[04:13 - 04:28] So let's write HTTP context and let's simply call it context. Since the purpose of this method is to catch an exception, we will create a try catch block.
[04:29 - 04:38] So first let's write try. If there is no exception, we will simply pass the context to our request delegate.
[04:39 - 04:56] So we will write await next and we will pass the context. Now this means the request will simply skip this middleware and go to the next stage.
[04:57 - 05:16] In case of catch, let me write catch and inside exception, let's call it ex. Let's import exception using system.
[05:17 - 05:32] First of all, I would like to log the exception using logger. So what we can do is logger.log error and I will write the exception and exception.message.
[05:33 - 06:08] This will then output it in our console and since we want to send this to the client, we can format it by writing context.response.content type and it will be application/json/json. We also want to set the status code for this error.
[06:09 - 06:27] So what we can do is again write context.response.statuscode and this will be equal to 500. We can simply write 500 here manually or we can create it from our server.
[06:28 - 06:47] So for that, what we will do is HTTP status code. Internal server error.
[06:48 - 06:56] It should be HTTP status code. Now let's import it using system.net.
[06:57 - 07:06] And since it should be an integer, we will cast it to be an integer. Now we can finally write our response.
[07:07 - 07:13] So we will create a variable called response. First we will check our environment.
[07:14 - 07:33] So what we can do is ENV.is development and we will use a ternary operator here . So if it is inside development, what we will do is new API exception.
[07:34 - 07:42] Let's import it from API.error response. So first of all, we will pass the status code.
[07:43 - 08:03] We can simply copy it from here and paste it here. We also want to send a message so we can write exception.message and the details which will be exception.stack trace.
[08:04 - 08:14] We have given it a property of string so we can make it a string by writing to string method. So this is it when we are in development.
[08:15 - 08:28] But when we are in production, we don't want to send so much information. We will simply pass the status code and everything else will be taken care of.
[08:29 - 08:52] Also we would serialize our response to Jason before sending it. So what I will do is we are Jason, Jason serializer dot serialize and I can pass the response.
[08:53 - 09:12] Let's import Jason serializer using system dot text dot Jason. Finally, we can write our response using await context dot response dot write async and we will simply pass the Jason here.
[09:13 - 09:18] All our responses should be camel case like the other ones. So we can make it camel case as well.
[09:19 - 10:01] What we will do is create a new variable called options. It will be equal to new Jason serializer options and inside property naming policy will be equal to Jason naming policy dot camel case and we will simply pass the options to our Jason.
[10:02 - 10:14] Let's go to the startup class now. This is checking if we are in development mode and it is responsible for showing us the stack trace which we saw in postman.
[10:15 - 10:28] We just have created an alternative to this. So what we can do is simply take that off and on top we will use our middleware instead.
[10:29 - 10:47] So we will write use middleware and inside we will write the exception middle ware. Let's import it using API dot middleware.
[10:48 - 10:54] We are now ready to test this out. Make sure the server is running and open postman.
[10:55 - 11:02] Let's run it again. We see the stack trace as string in our details property.
[11:03 - 11:09] What we also see is the status code and the error message. This is exactly as we wanted.
[11:10 - 11:18] The only thing left to be fixed is this validation error. So let's work on it next.