Introduction
ASP.NET Core is known for its high performance, modularity, and flexibility, and one of the key building blocks behind these strengths is Middleware.
Middleware forms the request–response pipeline in ASP.NET Core applications. Every HTTP request and response flows through this pipeline, making middleware a critical concept for any .NET Core developer.
In this article, we will explore:
What Is Middleware in ASP.NET Core?
Middleware is a software component that:
Handles HTTP requests and responses
Can inspect, modify, or short-circuit requests
Is executed sequentially in a pipeline
Each middleware component can:
Process the request
Call the next middleware
Process the response
Think of middleware as checkpoints that every request must pass through.
ASP.NET Core Request Pipeline
When a request hits an ASP.NET Core application:
It enters the middleware pipeline
Each middleware runs in the order it is registered
The response flows back in reverse order
Request → Middleware 1 → Middleware 2 → Middleware 3 → Controller
Response ← Middleware 1 ← Middleware 2 ← Middleware 3
The order of middleware registration is extremely important.
Common Built-in Middleware
ASP.NET Core provides several built-in middleware components:
| Middleware | Purpose |
|---|
UseRouting | Matches incoming requests to routes |
UseAuthentication | Authenticates users |
UseAuthorization | Authorizes users |
UseEndpoints | Executes matched endpoints |
UseExceptionHandler | Global exception handling |
UseStaticFiles | Serves static files |
Example pipeline in Program.cs:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseExceptionHandler("/error");
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
Types of Middleware
1. Inline Middleware
Defined directly using Use or Run.
app.Use(async (context, next) =>
{
// Before next middleware
await context.Response.WriteAsync("Before Middleware\n");
await next();
// After next middleware
await context.Response.WriteAsync("After Middleware\n");
});
2. Terminal Middleware
Does not call the next middleware.
app.Run(async context =>
{
await context.Response.WriteAsync("Request handled here.");
});
Once Run() is executed, the pipeline stops.
3. Custom Middleware
For reusable and clean code, create custom middleware.
Step 1: Create Middleware Class
public class RequestLoggingMiddleware
{
private readonly RequestDelegate _next;
public RequestLoggingMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
Console.WriteLine($"Request: {context.Request.Method} {context.Request.Path}");
await _next(context);
}
}
Step 2: Register Middleware
app.UseMiddleware<RequestLoggingMiddleware>();
Short-Circuiting the Pipeline
Middleware can stop further execution:
app.Use(async (context, next) =>
{
if (!context.User.Identity.IsAuthenticated)
{
context.Response.StatusCode = StatusCodes.Status401Unauthorized;
return;
}
await next();
});
This technique is commonly used in:
Authentication
Authorization
Rate limiting
Best Practices for Middleware
Register middleware in the correct order
Keep middleware lightweight
Use custom middleware for reusable logic
Avoid heavy business logic in middleware
Prefer exception-handling middleware at the top
Don’t perform long-running tasks
Don’t ignore async/await
Middleware vs Filters
| Middleware | Filters |
|---|
| Works on HTTP level | Works on MVC level |
| Applies globally | Applies to controllers/actions |
| Runs before routing | Runs after routing |
Use middleware for cross-cutting concerns like logging, security, and error handling.
Conclusion
Middleware is the backbone of ASP.NET Core. Understanding how it works empowers developers to:
Mastering middleware means mastering the ASP.NET Core request pipeline.