In the last post, we talked about what Middleware is, what it’s for, and simple ways of including it in our ASP.NET 6 app’s pipeline.

In this post, we’re going to expand on these fundamentals to build a few custom Middleware classes.

Standard Middleware Architecture

Unlike what we did in Part 1, most of the time we want to have our Middleware be separate classes, and not just additional lines in our Program.cs file.

Remember this middleware from Part 1? The one that returned a response consisting of “Hello world”?

Let’s create a custom middleware class that does the same thing.

Here’s a basic empty class we’ll use for this middleware:

A middleware class consists of three parts. First, any middleware class in ASP.NET 6 must include a private instance of RequestDelegate which is populated by the class’s constructor. Remember that RequestDelegate represents the next piece of middleware in the pipeline:

Second, the class must have an async method InvokeAsync() which takes an instance of HttpContext as its first parameter.

Third, the middleware must have its own unique implementation. For this middleware, all we want to do is return a custom response:

NOTE: within the InvokeAsync() method, most middleware will have a call to await next(context); any middleware that does not do this will be a terminal middleware, because the pipeline beyond that point will not be run. Since our SimpleResponseMiddleware does, in fact, want to stop the pipeline processing, it does not call await next(context).

Adding Middleware to the Pipeline

At this point, it is possible for us to wire up this middleware class to our app in the Program.cs file using the UseMiddleware<T>() method:

For very simple middleware classes, this is sufficient. However, often we use extension methods instead of UseMiddleware<T>() because they provide us with another layer of abstraction:

We would then use that extension method like so:

Either way of doing this is correct. I personally prefer the clarity and readability of the extension method route, but you can go with whatever you like better.

Building a Logging Middleware

One of the most common scenarios for middleware is logging, specifically logging of things like the request path or headers, culture, or response body.

The LoggingService Class

We’re going to build a logging middleware class that does two things:

  1. Log the request path.
  2. Log the distinct response headers.

First, we must create an interface ILoggingService and class LoggingService.

We then need to add LoggingService to the Services collection of the app in Program.cs:

Middleware classes can have services injected into them, just like normal classes.

The LoggingMiddleware Class

Now we need a LoggingMiddleware class which actually does the logging. First, let’s create a skeleton for the class LoggingMiddleware, which accepts an instance of ILoggingService as a parameter in the constructor:

Remember that we are recording the request’s path, and the response’s unique headers. That means we will have code on either side of the call to await next(context).

Adding LoggingMiddleware to the Pipeline

Finally, we need to call our new extension method in Program.cs to add the LoggingMiddleware class to the pipeline:

When we run the app, we can see (by setting breakpoints) that the code will correctly log both the request path and the response headers.

1 Comment

  1. Pingback: ASP.NET 6 Middleware - Pradeep Barli

Comments are closed.