MSDN .NET Documentation

Web Development Fundamentals

Understanding Middleware in ASP.NET Core

Middleware are components that process an HTTP request and response pipeline. Each piece of middleware can perform the following actions:

The ASP.NET Core web platform's request processing model is built around an ordered pipeline of middleware components. When a request comes in, it flows through the middleware components in order, and the response flows back through them in reverse order. This allows for a highly modular and customizable request handling process.

Key Concepts

The Request Pipeline

The request pipeline is a series of delegates, known as middleware components, that are invoked sequentially as the request is processed. Think of it as a chain reaction where each link performs a specific task.

Middleware Components

Each middleware component has access to the incoming request and the outgoing response. It can inspect, modify, or even terminate the request/response flow.

The `next` Delegate

A crucial part of middleware is the `next` delegate. This delegate represents the remainder of the request pipeline. A middleware component can choose to call `next` to pass the request further down the pipeline, or it can choose not to call `next` to short-circuit the pipeline (e.g., if it handles the request completely, like returning a specific error or static file).

Common Middleware Examples

Writing Custom Middleware

You can create your own middleware to implement custom logic. A common pattern for creating middleware is using a class with a constructor that accepts a `RequestDelegate` (the `next` delegate) and an `InvokeAsync` method that contains the middleware's logic.

Here's a simplified example of a custom middleware that logs the request path:


public class LoggingMiddleware
{
    private readonly RequestDelegate _next;

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

    public async Task InvokeAsync(HttpContext context)
    {
        Console.WriteLine($"Incoming request: {context.Request.Method} {context.Request.Path}");

        // Call the next middleware in the pipeline
        await _next(context);

        Console.WriteLine($"Outgoing response: {context.Response.StatusCode}");
    }
}
            

To use this middleware, you would register it in your application's startup configuration:


// In Startup.cs (or Program.cs in .NET 6+)
app.UseMiddleware<LoggingMiddleware>();
            
Note: The order in which you register middleware is crucial. It determines the order in which they will be executed in the pipeline. For example, authentication middleware should typically run before authorization middleware.

Middleware in the `Program.cs` / `Startup.cs` File

In modern ASP.NET Core applications, middleware is configured using the Use... extension methods on the IApplicationBuilder interface. The order of these calls defines the pipeline.


var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorPages(); // Example service

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles(); // Serves static files

app.UseRouting(); // Enables endpoint routing

app.UseAuthentication(); // Handles authentication
app.UseAuthorization(); // Handles authorization

// Custom middleware example
app.UseMiddleware<LoggingMiddleware>();

app.MapRazorPages(); // Maps Razor Pages endpoints

app.Run();
            
Tip: For common middleware like authentication, authorization, and routing, ASP.NET Core provides convenient extension methods that abstract away some of the boilerplate code. Always refer to the official documentation for the most up-to-date and recommended practices.