Introduction
In modern web applications built using ASP.NET Core Web API, handling requests and responses efficiently is very important. Every request that comes to your application passes through a pipeline before reaching the controller and then goes back through the same pipeline as a response.
This pipeline is called the Middleware Pipeline.
Sometimes, built-in middleware is not enough, and you need custom logic like:
Logging requests
Handling exceptions
Validating headers
Modifying responses
This is where Custom Middleware in ASP.NET Core becomes very useful.
In this article, we will learn how to create custom middleware in ASP.NET Core step by step in simple words, with real-world examples and best practices.
What is Middleware in ASP.NET Core?
Middleware is a component that handles HTTP requests and responses.
π It sits in the request pipeline and can:
Simple Flow
Request β Middleware 1 β Middleware 2 β Controller β Middleware β Response
π Each middleware decides whether to pass control to the next middleware.
Why Use Custom Middleware?
Sometimes you need logic that is not available by default.
1. Logging Requests and Responses
You can track every request coming into your API.
2. Global Exception Handling
Handle errors in one place instead of repeating try-catch everywhere.
3. Authentication or Header Validation
Check tokens or headers before processing the request.
4. Performance Monitoring
Measure how long each request takes.
π Custom middleware helps keep your code clean and reusable.
Types of Middleware in ASP.NET Core
1. Built-in Middleware
Examples:
UseRouting
UseAuthentication
UseAuthorization
2. Custom Middleware
Middleware created by developers to handle specific logic.
How to Create Custom Middleware in ASP.NET Core
Letβs implement a custom middleware step by step.
Step 1: Create Middleware Class
Create a new 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);
Console.WriteLine($"Response Status: {context.Response.StatusCode}");
}
}
Explanation
RequestDelegate β Represents the next middleware
InvokeAsync β Main method executed for every request
HttpContext β Contains request and response data
π Always call _next(context) to continue the pipeline.
Step 2: Register Middleware in Program.cs
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseMiddleware<RequestLoggingMiddleware>();
app.MapControllers();
app.Run();
Important Note
Middleware order matters!
π The order you add middleware defines execution flow.
Step 3: Run and Test
When you call any API endpoint, you will see logs like:
π This confirms middleware is working.
Creating a Reusable Extension Method (Best Practice)
To keep Program.cs clean, use extension methods.
public static class MiddlewareExtensions
{
public static IApplicationBuilder UseRequestLogging(this IApplicationBuilder builder)
{
return builder.UseMiddleware<RequestLoggingMiddleware>();
}
}
Use in Program.cs
app.UseRequestLogging();
π Cleaner and more readable code.
Real-World Example: Exception Handling Middleware
Letβs create a global exception handler.
public class ExceptionMiddleware
{
private readonly RequestDelegate _next;
public ExceptionMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception ex)
{
context.Response.StatusCode = 500;
context.Response.ContentType = "application/json";
var response = new
{
message = "Something went wrong",
detail = ex.Message
};
await context.Response.WriteAsJsonAsync(response);
}
}
}
Why This is Useful?
Middleware Execution Order in ASP.NET Core
Order is very important in ASP.NET Core Middleware Pipeline.
Example
app.UseMiddleware<ExceptionMiddleware>();
app.UseMiddleware<RequestLoggingMiddleware>();
π Exception middleware should come first to catch all errors.
Best Practices for Custom Middleware in ASP.NET Core
1. Keep Middleware Lightweight
Do not write heavy logic inside middleware.
2. Always Call Next Middleware
If you donβt call _next(context), request will stop.
3. Use Dependency Injection
Inject services like logging, database, etc.
4. Handle Exceptions Properly
Use try-catch for safe execution.
5. Maintain Proper Order
Execution depends on registration order.
Common Mistakes to Avoid
β Forgetting to call _next(context)
β Writing too much logic inside middleware
β Wrong middleware order
β Not handling exceptions
Real-World Use Cases
In real applications, middleware is used for:
Logging
Authentication
Authorization
Error handling
Request validation
π Almost every production-level ASP.NET Core Web API uses middleware.
Summary
Custom middleware in ASP.NET Core is a powerful way to handle cross-cutting concerns like logging, error handling, and request processing. By creating your own middleware, you can build clean, reusable, and scalable applications. Understanding how the middleware pipeline works and following best practices ensures that your application performs efficiently and remains easy to maintain.