Arctic Algorithm
3 min readDec 10, 2023

ASP.net Core Middleware in simpler terms

Middleware in .net applications

Middleware is a crucial part of ASP.NET Core or (.net 5 and 5++.. versions) applications, serving as the backbone for handling HTTP requests and responses. Let’s break down this concept into simple terms, using everyday analogies and straightforward code examples. I will use ASP.Net Core here on afterwards in this article to opt out legacy .net framework.

What is Middleware?

Imagine a car wash. Your car (the HTTP request) enters, goes through various cleaning stages (middleware), and comes out shiny and clean (the HTTP response). In ASP.NET Core, middleware components are like these stages in the car wash, each performing specific tasks on the incoming request and, eventually, on the outgoing response.

The Unified Pipeline

Middleware in ASP.NET Core operates within a single, unified pipeline, handling both the incoming request and the outgoing response. It’s like a production line in a factory where a product is built (request handled) and then packaged (response prepared) before shipping.

HttpContext: The Heart of Middleware

Each middleware has access to HttpContext, which contains Request and Response properties. It’s like a toolbox that each worker (middleware) on the factory line uses. They can either use tools to work on the product (request) or to package it (response).

The Key: await next(context)

This is the signal in your code that says, “I’m done with my part; pass it along to the next worker.” It keeps the production line moving.

Before await next(context)

This is where middleware acts on the incoming request. It’s like the initial stages of the car wash, where your car is soaked and scrubbed. Here’s a simple code example:

public async Task InvokeAsync(HttpContext context)
{
// Log the incoming request
LogRequestDetails(context.Request);
// Continue to the next middleware
await _next(context);
}

After await next(context)

Once the next delegate in the pipeline is awaited, any code that follows is acting on the outgoing response. It’s like the final stages of the car wash, where your car is rinsed and dried. Here’s how it looks in code:

public async Task InvokeAsync(HttpContext context)
{
// Call the next middleware
await _next(context);
// Add a custom header to the response
context.Response.Headers.Add("X-Custom-Header", "Value");
}

Request-Focused Middleware

When you want to deal exclusively with the request, put all your logic before the await next(context) line, like pre-washing the car before it hits the soap suds.

Response-Focused Middleware

For handling just the response, all your logic will go after the await next(context) line, like applying wax after the car is clean.

As you can see, putting your code before and after next(context) will do the trick. And also do not forget, if you want to access the request , you have to check, change or do anything with the request ,use Context.Request and if you want to use the response, use Context.Response

Middleware Template

Here’s a template for creating custom middleware

public class CustomMiddleware
{
private readonly RequestDelegate _next;
public CustomMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
// Perform actions on the request here
await _next(context); // Hand off to the next stage
// Perform actions on the response here
}
}

In Summary

Middleware is like a team of specialists, each with a specific job. The await next(context) command is the baton pass in a relay race, ensuring smooth transitions between stages. This flexible system lets you precisely control how your application handles HTTP traffic, offering powerful customization options at every step of the way.