C sharp - Building Custom Middleware in ASP.NET Core Pipeline
In ASP.NET Core, middleware components are fundamental building blocks that handle HTTP requests and responses. The middleware pipeline is a sequence of components that process incoming requests one by one and generate responses. Each middleware has the ability to perform operations before and after passing control to the next component in the pipeline.
Custom middleware allows developers to insert their own logic into this pipeline to handle cross-cutting concerns such as logging, authentication, error handling, request modification, or response transformation.
Understanding the Middleware Pipeline
When a request is sent from a client to an ASP.NET Core application, it travels through a chain of middleware components configured in the application startup. Each middleware decides whether to pass the request to the next middleware or terminate the pipeline by returning a response.
The order of middleware registration is extremely important because each component interacts with the request and response in sequence.
Structure of Custom Middleware
A custom middleware typically consists of:
-
A class that defines the middleware logic
-
A constructor that accepts a delegate representing the next middleware
-
A method (commonly named Invoke or InvokeAsync) that processes the request
The middleware class receives an HttpContext object, which contains all information about the current HTTP request and response.
Example of Custom Middleware
Below is a simple example of a custom middleware that logs request details:
public class RequestLoggingMiddleware
{
private readonly RequestDelegate _next;
public RequestLoggingMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
Console.WriteLine("Request: " + context.Request.Path);
await _next(context);
Console.WriteLine("Response Status: " + context.Response.StatusCode);
}
}
In this example, the middleware logs the request path before passing control to the next middleware and logs the response status after the next middleware has processed the request.
Registering Middleware in the Pipeline
To use custom middleware, it must be added to the application's pipeline, usually in the Program.cs file:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseMiddleware<RequestLoggingMiddleware>();
app.Run();
Middleware is executed in the order it is added. If multiple middleware components are registered, they form a chain.
Creating Middleware as an Extension Method
For better readability and reuse, middleware is often registered using an extension method:
public static class MiddlewareExtensions
{
public static IApplicationBuilder UseRequestLogging(this IApplicationBuilder builder)
{
return builder.UseMiddleware<RequestLoggingMiddleware>();
}
}
Then it can be used like this:
app.UseRequestLogging();
Short-Circuiting the Pipeline
A middleware can stop further processing by not calling the next delegate. This is known as short-circuiting. It is useful in scenarios like authentication or validation failures.
Example:
public async Task InvokeAsync(HttpContext context)
{
if (!context.Request.Headers.ContainsKey("Authorization"))
{
context.Response.StatusCode = 401;
await context.Response.WriteAsync("Unauthorized");
return;
}
await _next(context);
}
In this case, the request will not proceed further if the authorization header is missing.
Built-in Middleware vs Custom Middleware
ASP.NET Core provides many built-in middleware components such as routing, authentication, static file handling, and exception handling. However, custom middleware is useful when:
-
The requirement is application-specific
-
Existing middleware does not provide needed functionality
-
There is a need to centralize repeated logic
Middleware Execution Flow
Each middleware typically has two phases:
-
Incoming request processing (before calling the next middleware)
-
Outgoing response processing (after the next middleware completes)
This allows middleware to modify both requests and responses.
Best Practices
-
Keep middleware focused on a single responsibility
-
Ensure proper ordering in the pipeline
-
Avoid heavy processing to maintain performance
-
Use asynchronous programming to prevent blocking
-
Handle exceptions carefully to avoid breaking the pipeline
Conclusion
Custom middleware in ASP.NET Core provides a powerful way to control how HTTP requests and responses are handled. By understanding how the middleware pipeline works and how to insert custom components into it, developers can build flexible and maintainable web applications.