ASP.NET Core Middleware

Middleware components form the request processing pipeline in ASP.NET Core. Each middleware component has access to the request and response objects and can perform actions such as:

Understanding the Middleware Pipeline

ASP.NET Core applications use a pipeline of middleware components to handle incoming HTTP requests. The pipeline is configured in the Startup.cs (or Program.cs in .NET 6+) file using the UseMiddleware<T> extension method or by calling specific extension methods like UseStaticFiles(), UseRouting(), and UseEndpoints().

How Middleware Works

Each middleware component is responsible for a specific task. When a request arrives, it passes through the middleware components in the order they are configured. The first middleware component can:

  1. Perform operations on the request.
  2. Optionally, invoke the next middleware component in the pipeline by calling the next() delegate.
  3. If next() is called, perform operations on the response.

If a middleware component doesn't call the next delegate, the request processing stops at that component. This is known as short-circuiting.

Common Middleware Examples

Static Files Middleware

Serves static files (HTML, CSS, JavaScript, images) from the web root. You typically add this early in the pipeline.


app.UseStaticFiles();
            

Routing Middleware

Processes incoming requests to match them with an endpoint. This is crucial for MVC and Razor Pages.


app.UseRouting();
            

Authentication Middleware

Handles authentication logic, such as validating credentials and setting the principal for the request.


app.UseAuthentication();
            

Authorization Middleware

Enforces authorization policies based on the authenticated user's identity.


app.UseAuthorization();
            

Endpoints Middleware

Executes the matched endpoint handler (e.g., MVC controller action, Razor Page handler).


app.UseEndpoints(endpoints =>
{
    endpoints.MapRazorPages();
    endpoints.MapControllers();
    endpoints.MapGet("/", async context => await context.Response.WriteAsync("Hello World!"));
});
            

Creating Custom Middleware

You can create your own middleware to implement custom logic. A middleware component can be implemented as:

Example: Custom Logging Middleware

This middleware logs the request path before calling the next middleware and logs the response status code after.


public class LoggingMiddleware
{
    private readonly RequestDelegate _next;

    public LoggingMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        Console.WriteLine($"--> Request starting: {context.Request.Method} {context.Request.Path}");
        await _next(context);
        Console.WriteLine($"<-- Response finished: {context.Response.StatusCode}");
    }
}

// In Startup.cs or Program.cs:
// app.UseMiddleware();
            
Note: The order of middleware matters significantly. Place middleware in the order they should execute for your application's logic. For example, authentication should typically come before authorization.

Middleware Order

The middleware pipeline is executed in the order in which it is configured. Consider the following order:

  1. UseStaticFiles() (to serve static content directly)
  2. UseRouting() (to match the request to an endpoint)
  3. UseAuthentication() (to authenticate the user)
  4. UseAuthorization() (to authorize the user for the endpoint)
  5. UseEndpoints() (to execute the endpoint handler)

Short-Circuiting the Pipeline

Some middleware can prevent further processing of the request if certain conditions are met. For example, if a user is not authorized, the authorization middleware might short-circuit the pipeline and return an unauthorized response.

Resources