The middleware pipeline

2 min read
On trails:ASPNETstep 2/7

The idea

The ASP.NET Core request processing pipeline is made of a sequence of middleware components. Each middleware has access to the incoming HttpContext, and can do work before or after it invokes the next middleware in the pipeline. A middleware component can pass the request on to the next component, or short-circuit the pipeline by generating a response itself.

Order matters

The order in which middleware components are added to the pipeline in Program.cs (through IApplicationBuilder) is critical. Requests flow through the pipeline in the order components are added, and responses flow back in the reverse order. The order affects security, performance and functionality.

For example, authentication middleware must run before authorization middleware. Exception handling middleware should typically be placed early in the pipeline, to catch exceptions from later components.

Common built-in middleware

Method What it does
UseDeveloperExceptionPage() Displays detailed error information for developers during development.
UseExceptionHandler() Catches exceptions in production, and typically redirects to an error page.
UseHsts() Adds HTTP Strict Transport Security headers.
UseHttpsRedirection() Redirects HTTP requests to HTTPS.
UseStaticFiles() Serves static files (CSS, JavaScript, images) from the wwwroot folder.
UseRouting() Adds route matching capabilities to the pipeline.
UseCors() Configures Cross-Origin Resource Sharing.
UseAuthentication() Attempts to establish the user’s identity.
UseAuthorization() Verifies whether the authenticated user is permitted to access a resource.
UseSession() Enables session state management.
UseEndpoints() Adds endpoint execution to the pipeline, for example mapping requests to controller actions or Razor Pages.

Custom middleware

You can write custom middleware to handle specific cross-cutting concerns. The usual way is a class with an InvokeAsync(HttpContext context, RequestDelegate next) method, or Invoke for synchronous middleware, registered with app.UseMiddleware<YourCustomMiddleware>(). You can also register it inline with app.Use.

C#
app.UseMiddleware<YourCustomMiddleware>(); app.Use(async (context, next) =>{    ...    await next.Invoke();    ...});

Use() versus Run()

Use() adds a middleware that can optionally call the next delegate to pass control to the next middleware in the pipeline. Run() adds a terminal middleware: it always short-circuits the pipeline and never calls next.


Sources