Creating Custom Middleware in ASP.Net Core
Tags: csharp
Published: 2021-10-02 09:15:32

Middleware is a software that's assembled into an app pipeline to handle requests and responses. Each component:
- Chooses whether to pass the request to the next component in the pipeline.
- Can perform work before and after the next component in the pipeline.

Request delegates are used to build the request pipeline and are configured using  [Run](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.builder.runextensions.run?view=aspnetcore-5.0) ,  [Map ](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.builder.mapextensions.map?view=aspnetcore-5.0) and  [Use](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.builder.useextensions.use?view=aspnetcore-5.0)  extension methods.

The `ASP.Net Core` request pipeline consists of a sequence of request delegates, called one after the other. The following diagram from Microsoft docs demonstrates the concept. The thread of execution follows the black arrows.


![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1633165405095/litZrnfGX.png)

#### Create custom middleware
Lets consider the following middleware example configured in the `Startup.cs` which sets the culture for the current request from `Claims` of `HttpContext`.

```csharp
public class Startup
{
    public void Configure(IApplicationBuilder app)
    {
        app.Use(async (context, next) =>
        {
           var claims = context?.User?.Claims?.ToList();

            // Get cultureId out of claims.
            // If not set then fallback to en-US
            var cultureId = claims.
                ?FirstOrDefault(claim => claim.Type == "CultureId")
                ?.Value 
            ?? "en-US";

            // Retrieve a read-only instance of culture
            // using the specified culture name
            var cultureInfo = CultureInfo.GetCultureInfo(cultureId);

            CultureInfo.CurrentCulture = cultureInfo;
            CultureInfo.CurrentUICulture = cultureInfo;

            // Call the next delegate/middleware in the pipeline
            await next();
        });
    }
}
```
Now we can extract the above middleware delegate into a class. Our middleware class must include:
- A public constructor with a parameter of type RequestDelegate
- A public method named `Invoke` or `InvokeAsync`. This method must return a `Task` accept a first parameter of type `HttpContext`

```csharp
public class TokenCultureMiddleware
{
    private readonly RequestDelegate _next;

    public TokenCultureMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        var claims = context?.User?.Claims?.ToList();

        // Get cultureId out of claims.
        // If not set then fallback to en-US
        var cultureId = claims.
            ?FirstOrDefault(claim => claim.Type == "CultureId")
            ?.Value 
        ?? "en-US";

        // Retrieve a read-only instance of culture
        // using the specified culture name
        var cultureInfo = CultureInfo.GetCultureInfo(cultureId);

        CultureInfo.CurrentCulture = cultureInfo;
        CultureInfo.CurrentUICulture = cultureInfo;

        // Call the next delegate/middleware in the pipeline
        await _next.Invoke(context);
    }
}
```
#### Middleware extension method
Last we can create a middleware extension method and call our custom middleware from `Startup.Configure`
```csharp
public static class TokenCultureMiddlewareExtensions
{
    public static IApplicationBuilder UseTokenCulture(
        this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<TokenCultureMiddleware>();
    }
}
```
And in `Startup.Configure`
```csharp
public class Startup
{
    public void Configure(IApplicationBuilder app)
    {
        // Call our extension method
        app.UseTokenCulture();
    }
}
```