Middleware
1.What is Middleware
Middleware is software assembled into the ASP.NET Core request pipeline to handle HTTP requests and responses.
Each middleware component can:
- Decide whether to pass the request to the next component
- Perform work before and after the next component executes
The pipeline looks like this:
Request
↓
Middleware A
↓
Middleware B
↓
Middleware C
↓
Endpoint (Controller)
↓
Response
A middleware component typically has this structure:
app.Use(async (context, next) =>
{
Console.WriteLine("Before");
await next(); // invoke next middleware
Console.WriteLine("After");
});
This allows middleware to implement a pre-processing / post-processing pattern.
2.Inline Middleware vs Class-based Middleware
Middleware can be written in two ways.
Inline middleware
This style is useful for simple logic.
app.Use(async (context, next) =>
{
await next();
});
Class-based middleware
Reusable middleware is usually encapsulated in a class:
public class MyMiddleware
{
private readonly RequestDelegate _next;
public MyMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
// pre-processing
await _next(context);
// post-processing
}
}
Registered with:
app.UseMiddleware<MyMiddleware>();
3.Terminal Middleware and Short-Circuiting
If middleware does not call next(), the pipeline stops.
This is called short-circuiting, and the middleware becomes a terminal middleware.
Example:
app.Run(async context =>
{
await context.Response.WriteAsync("End");
});
Any middleware registered after this will never execute.
4.Use vs Run vs Map
ASP.NET Core provides several methods to build the pipeline.
Use
Adds middleware and allows the request to continue.
app.Use(async (context, next) =>
{
await next();
});
Run
Adds a terminal middleware that ends the pipeline.
app.Run(async context =>
{
await context.Response.WriteAsync("End");
});
Map
Creates a branch pipeline based on the request path.
app.Map("/hello", branch =>
{
branch.Run(async context =>
{
await context.Response.WriteAsync("Hello branch");
});
});
Only requests matching /hello will enter this branch pipeline.
5.Why ASP.NET Core Does Not Require a Middleware Interface
ASP.NET Core does not enforce a specific interface such as IMiddleware for middleware components.
Reason 1: Flexibility
The framework supports both:inline delegate middleware, class-based middleware.
If a strict interface were required, inline middleware would not be possible.Reason 2: Convention-based invocation
ASP.NET Core locates and invokes Invoke or InvokeAsync methods via reflection.
As long as the method signature is correct, the middleware can be executed without requiring a specific interface.
This design keeps the middleware system lightweight and flexible.
6.Routing, Authentication and Authorization Middleware
Routing Middleware
UseRouting() matches incoming requests to endpoints.
It:examines the request URL, selects the endpoint, stores it in HttpContext.
Important: UseRouting() does not execute the endpoint.
Execution happens later via:
UseEndpoints()
MapControllers()
Without routing middleware, ASP.NET Core cannot determine which controller should handle the request.
Authentication Middleware
UseAuthentication():reads the Authorization header, validates the token (e.g., JWT), populates HttpContext.User;
It does not block the request, It only sets the authentication state.
Authorization Middleware
UseAuthorization() checks whether the user has permission to access the endpoint.
If authorization fails, the middleware returns:
401 Unauthorized
or
403 Forbidden
Correct order:
UseRouting
UseAuthentication
UseAuthorization
Filters
Filters operate at the MVC level, not the HTTP pipeline level.They run inside the controller execution pipeline.
Filter types:
- Authorization Filters: Execute early in the pipeline to determine whether the user is authorized to access the resource.
- Resource Filters: Run before and after the rest of the filter pipeline and action execution; used for caching, resource management, or short-circuiting the request.
- Action Filters: Execute code before and after the action method runs; commonly used for logging, validation, or modifying action parameters/results.
- Exception Filters: Handle exceptions thrown during action execution or later filters; used to implement centralized error handling.
- Result Filters: Run before and after the action result executes; often used to modify the response, such as adding headers or transforming the result.
The following diagram shows how filter types interact in the filter pipeline:

Difference from Middleware:
Q: Must I use Exception Filters? Isn’t middleware better for handling exceptions?
A: If your project is purely an API, it’s recommended to use middleware for centralized exception handling. However, if you need special handling for certain controllers or need to access the ActionContext during exceptions, Exception Filters are more suitable.
Core comparison: Exception Middleware vs. Exception Filters
Middleware is a system-level HTTP request pipeline controller that can do anything you want; filters are application-level lifecycle hooks that can only insert logic at the predefined “points” defined by Microsoft.
Why is it said that performing authorization in an ActionFilter is "too late"?
Performing authorization checks in an ActionFilter is considered "too late" because ActionFilters run after the routing and model binding stages, meaning the request has already been processed to some extent. By this time, critical resources may have already been allocated, and some business logic might have started executing. This can lead to unnecessary processing or potential security risks if unauthorized requests are only caught at this late stage.
In contrast, authorization is typically done earlier in the pipeline (e.g., via middleware or Authorization Filters), so that unauthorized requests can be rejected as soon as possible—before consuming more resources or exposing sensitive logic. This improves efficiency and enhances security.
Top comments (0)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.