# 3 Ways To Create Middleware In ASP.NET Core

> Middleware allows us to introduce additional logic before or after executing an HTTP request. I'm going to show you three approaches to define custom middleware in ASP.NET Core: with request delegates, by convention, and factory-based.

Published: 2022-10-01. Author: Milan Jovanović.

Canonical: https://milanjovanovic.tech/blog/3-ways-to-create-middleware-in-asp-net-core

In this newsletter, we'll be covering three ways to create middleware in **ASP.NET Core** applications.

**Middleware** allows us to introduce additional logic before or after executing an HTTP request.

You are already using many of the built-in middleware available in the framework.

I'm going to show you three approaches to how you can define custom middleware:

- [With Request Delegates](#adding-middleware-with-request-delegates)
- [By Convention](#adding-middleware-by-convention)
- [Factory-Based](#adding-factory-based-middleware)

Let's go over each of them and see how we can implement them in code.

## Adding Middleware With Request Delegates

The first approach to defining a middleware is by writing a **Request Delegate**.

You can do that by calling the `Use` method on the `WebApplication` instance
and providing a lambda method with two arguments.
The first argument is the `HttpContext` and the second argument is
the actual next request delegate in the pipeline `RequestDelegate`.

Here's what this would look like:

```csharp
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Use(async (context, next) =>
{
    // Add code before request.

    await next(context);

    // Add code after request.
});
```

By awaiting the `next` delegate, you are continuing the request pipeline execution.
You can _short-circuit_ the pipeline by not invoking the `next` delegate.

This overload of the `Use` method is the one suggested by **Microsoft**.

## Adding Middleware By Convention

The second approach requires us to create a class that will represent our middleware.
We have to follow the convention when creating this class so that we can use it as middleware in our application.

I'm first going to show you what this class looks like, and then explain what is the convention we are following here.

Here's how this class would look like:

```csharp
public class ConventionMiddleware(
    RequestDelegate next,
    ILogger<ConventionMiddleware> logger)
{
    public async Task InvokeAsync(HttpContext context)
    {
        logger.LogInformation("Before request");

        await next(context);

        logger.LogInformation("After request");
    }
}
```

The convention we are following has a few rules:

- We need to inject a `RequestDelegate` in the constructor
- We need to define an `InvokeAsync` method with an `HttpContext` argument
- We need to invoke the `RequestDelegate` and pass it the `HttpContext` instance

There's one more thing that's required, and that is to tell our application to use this middleware.

We can do that by calling the `UseMiddleware` method:

```csharp
app.UseMiddleware<ConventionMiddleware>();
```

And with this, we have a functioning middleware.

## Adding Factory-Based Middleware

The third and last approach requires us to also create a class that will represent our middleware.

However, this time we're going to implement the `IMiddleware` interface.
This interface has only one method - `InvokeAsync`.

Here's what this class would like:

```csharp
public class FactoryMiddleware(ILogger<FactoryMiddleware> logger) : IMiddleware
{
    public async Task InvokeAsync(HttpContext context, RequestDelegate next)
    {
        logger.LogInformation("Before request");

        await next(context);

        logger.LogInformation("After request");
    }
}
```

The `FactoryMiddleware` class will be resolved at runtime from dependency injection.

Because of this, we need to register it as a service:

```csharp
builder.Services.AddTransient<FactoryMiddleware>();
```

And like the previous example, we need to tell our application to use our factory-based middleware:

```csharp
app.UseMiddleware<FactoryMiddleware>();
```

With this, we have a functioning middleware.

## A Word On Strong Typing

I'm a big fan of **strong typing** whenever possible.
Out of the three approaches I just showed you, the one using the
`IMiddleware` interface satisfies this constraint the most.
This is also my **preferred** way to implement **middleware**.

Since we're implementing an interface, it's very easy to create
a generic solution to never forget to register your middleware.

You can use reflection to scan for classes implementing
the `IMiddleware` interface and add them to dependency injection,
and also add them to the application by calling `UseMiddleware`.

---

## Frequently asked questions

### What is middleware in ASP.NET Core?

Middleware lets you run additional logic before or after an HTTP request executes. Requests flow through a pipeline of middleware components, and you are already using many of the built-in middleware that ship with the framework.

### What are the three ways to create custom middleware in ASP.NET Core?

You can write a request delegate inline with the Use method, create a convention-based class with an injected RequestDelegate and an InvokeAsync method, or create a factory-based class that implements the IMiddleware interface and is resolved from dependency injection.

### How does convention-based middleware work?

You create a class that injects a RequestDelegate in its constructor, defines an InvokeAsync method accepting an HttpContext, and invokes the delegate to continue the pipeline. You then register the class with the UseMiddleware method on the application.

### Why prefer factory-based middleware with IMiddleware?

Factory-based middleware implements the strongly typed IMiddleware interface and is resolved from dependency injection at runtime, so it must also be registered as a service. Because it is interface-based, you can use reflection to scan for implementations and register them automatically.

### How do you short-circuit the ASP.NET Core request pipeline?

Inside a middleware, do not invoke the next request delegate. Awaiting the next delegate continues pipeline execution, while skipping the call stops the request from reaching the remaining middleware.
