Middleware

Middleware is software that's assembled into an app pipeline to handle requests and responses. Each component performs operations on an HttpContext and:

  • Chooses whether to pass the request to the next component in the pipeline.

  • Can perform work before and after the next component in the pipeline.

Request delegates are used to build the request pipeline. The request delegates handle each HTTP request. Request delegates are configured using Run, Map, and Use extension methods.

An individual request delegate can be specified in-line as an anonymous method (called in-line middleware), or it can be defined in a reusable class. These reusable classes and in-line anonymous methods are middleware, also called middleware components. Each middleware component in the request pipeline is responsible for invoking the next component in the pipeline or short-circuiting the pipeline. When a middleware short-circuits, it's called a terminal middleware because it prevents further middleware from processing the request.

The request handling pipeline is composed as a series of middleware components. Each component performs operations on an HttpContext and either invokes the next middleware in the pipeline or terminates the request.

Program.cs
var builder = WebApplication.CreateBuilder(args);

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

var app = builder.Build();

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

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

app.UseAuthorization();

app.MapGet("/hi", () => "Hello!");

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();
  • Chain multiple request delegates together with Use. The next parameter represents the next delegate in the pipeline. You can short-circuit the pipeline by not calling the next parameter.

  • When a delegate doesn't pass a request to the next delegate, it's called short-circuiting the request pipeline. Short-circuiting is often desirable because it avoids unnecessary work. For example, Static File Middleware can act as a terminal middleware by processing a request for a static file and short-circuiting the rest of the pipeline.

Middleware order for ASP.NET Core MVC and Razor Pages apps

If you don't call app.UseRouting, the Routing middleware runs at the beginning of the pipeline by default.

The Endpoint middleware in the preceding diagram executes the filter pipeline for the corresponding app type—MVC or Razor Pages.

  • Map extensions are used as a convention for branching the pipeline. Map branches the request pipeline based on matches of the given request path. If the request path starts with the given path, the branch is executed.

    • Map supports nesting.

    • Map can also be used to match multiple segments at once.

    • MapWhen branches the request pipeline based on the result of the given predicate.

The following table shows the requests and responses from http://localhost:1234 using the preceding code.

Request
Response

localhost:1234

Hello from non-Map delegate.

localhost:1234/map1

Map Test

localhost:1234/map1/seg1

Multiple Segment Test

localhost:1234/?branch=main

Branch used = main

localhost:1234/map3

Hello from non-Map delegate.

When Map is used, the matched path segments are removed from HttpRequest.Path and appended to HttpRequest.PathBase for each request.

  • Run delegates don't receive a next parameter. The first Run delegate is always terminal and terminates the pipeline. Some middleware components may expose Run[Middleware] methods that run at the end of the pipeline:

  • If another Use or Run delegate is added after the Run delegate, it's not called.

Test Middleware

Middleware can be tested in isolation with TestServer. It allows you to:

  • Instantiate an app pipeline containing only the components that you need to test.

  • Send custom requests to verify middleware behavior.

Custom Middleware

Creating a middleware component by calling Microsoft.AspNetCore.Builder.UseExtensions.Use. The Use extension method adds a middleware delegate defined in-line to the application's request pipeline.

There are two overloads available for the Use extension:

  • One takes a HttpContext and a Func<Task>. Invoke the Func<Task> without any parameters.

  • The other takes a HttpContext and a RequestDelegate. Invoke the RequestDelegate by passing the HttpContext.

Last updated

Was this helpful?