ASP.NET Core Request Pipeline

The ASP.NET Core request pipeline is the fundamental mechanism by which incoming HTTP requests are processed and outgoing HTTP responses are generated. It's a series of components, known as middleware, that are executed sequentially for each request.

Understanding the Pipeline

When a request arrives at your ASP.NET Core application, it enters the pipeline at the beginning and passes through each middleware component. Each middleware has the opportunity to:

Key Components and Concepts

Middleware

Middleware is the building block of the ASP.NET Core pipeline. Each piece of middleware is responsible for a specific task, such as:

Middleware components are arranged in a specific order within the pipeline. This order is critical, as it determines the sequence of operations. For example, authentication middleware typically runs before authorization middleware.

Use...() Extension Methods

You configure the ASP.NET Core pipeline in your application's Startup.cs (or Program.cs in .NET 6+) file using extension methods on the IApplicationBuilder interface. These methods, like app.UseStaticFiles(), app.UseRouting(), and app.UseAuthentication(), add specific middleware to the pipeline.


// Example in Startup.cs (older .NET Core versions)
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
        endpoints.MapControllers();
    });
}

// Example in Program.cs (.NET 6 and later)
var builder = WebApplication.CreateBuilder(args);

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

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.MapRazorPages();
app.MapControllers();

app.Run();
            

Order Matters

The order in which you add middleware is crucial. Consider the following example:

Note: If you place app.UseRouting() after middleware that might short-circuit the request (like app.Run()), routing will never be reached. Similarly, app.UseAuthentication() and app.UseAuthorization() must come after app.UseRouting() so that the router can determine which endpoints need authentication/authorization.

Terminal Middleware

Some middleware, often added last, can terminate the pipeline. For instance, app.Run() is a simple middleware that takes a delegate and executes it, but it doesn't call the next middleware in the pipeline.


app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from the terminal middleware!");
});
            

Common Middleware Components

Custom Middleware

You can create your own custom middleware to add specific functionality to your application. A middleware component is typically a class with a constructor that accepts RequestDelegate and an InvokeAsync method that processes the HttpContext.


public class CustomMiddleware
{
    private readonly RequestDelegate _next;

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

    public async Task InvokeAsync(HttpContext context)
    {
        // Code to execute before the next middleware
        Console.WriteLine($"Request Path: {context.Request.Path}");

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

        // Code to execute after the next middleware (response processing)
        Console.WriteLine($"Response Status Code: {context.Response.StatusCode}");
    }
}

// In Startup.cs (or Program.cs):
// app.UseMiddleware<CustomMiddleware>();
            
Tip: For simple middleware logic, you can often use the Use() or UseWhen() extension methods directly in your pipeline configuration without creating a separate class.

Benefits of the Pipeline Architecture

Important: Understanding the order and purpose of middleware is fundamental to building robust and efficient ASP.NET Core applications. Always refer to the official documentation for the most up-to-date information on specific middleware and their configurations.

This document provides a high-level overview of the ASP.NET Core request pipeline. For detailed information on specific middleware or advanced customization, please explore the related topics in the navigation pane.