# How the Middleware Pipeline Is Configured in ASP.NET Core: Inside ApplicationBuilder

> Learn how ASP.NET Core configures its middleware pipeline with ApplicationBuilder. Understand how RequestDelegate instances are chained and wrapped when Build() is called.

- Repository: [.NET Platform/aspnetcore](https://github.com/dotnet/aspnetcore)
- Tags: internals
- Published: 2026-07-13

---

**ASP.NET Core configures the middleware pipeline using `ApplicationBuilder` to chain `RequestDelegate` instances, constructing the pipeline by wrapping components in reverse order when `Build()` is called.**

The configuration of the middleware pipeline is a fundamental aspect of ASP.NET Core development, implemented within the `dotnet/aspnetcore` repository through the `IApplicationBuilder` abstraction. Understanding how `ApplicationBuilder` stores, orders, and compiles middleware components reveals why the ordering of statements in [`Program.cs`](https://github.com/dotnet/aspnetcore/blob/main/Program.cs) directly impacts request processing behavior.

## The ApplicationBuilder Foundation

The `ApplicationBuilder` class, located in [`src/Http/Http/src/Builder/ApplicationBuilder.cs`](https://github.com/dotnet/aspnetcore/blob/main/src/Http/Http/src/Builder/ApplicationBuilder.cs), serves as the concrete implementation of `IApplicationBuilder`. This class maintains the ordered collection of middleware and handles the final compilation into an executable request processor.

### Storing Middleware Components

Inside [`ApplicationBuilder.cs`](https://github.com/dotnet/aspnetcore/blob/main/ApplicationBuilder.cs), the class maintains a private readonly list called `_components` that stores each middleware registration:

```csharp
private readonly List<Func<RequestDelegate, RequestDelegate>> _components = new();

```

Every call to `IApplicationBuilder.Use` appends a `Func<RequestDelegate, RequestDelegate>` to this list. This delegate represents a middleware factory that accepts the next `RequestDelegate` in the chain and returns a new `RequestDelegate` wrapping the current middleware's logic.

### Building the Pipeline in Reverse

When the application starts, `ApplicationBuilder.Build()` walks through the `_components` list **backwards** (lines 164-200 in [`ApplicationBuilder.cs`](https://github.com/dotnet/aspnetcore/blob/main/ApplicationBuilder.cs)). It begins with a terminal `RequestDelegate` that sets the `__RequestUnhandled` flag and returns a 404 response, then iteratively wraps each preceding middleware around it:

```csharp
// Simplified logic from ApplicationBuilder.cs lines 164-200
RequestDelegate app = context =>
{
    context.Items[RequestUnhandledKey] = true; // __RequestUnhandled
    return Task.CompletedTask;
};

for (int c = _components.Count - 1; c >= 0; c--)
{
    app = _components[c](app);
}

return app;

```

This reverse construction ensures that the order of execution matches the registration order: the first middleware registered becomes the outermost wrapper, while the last registered sits closest to the terminal delegate.

## Registering Middleware Components

ASP.NET Core offers multiple patterns for adding middleware to the pipeline, each resolved through different mechanisms in the `UseMiddlewareExtensions` class.

### Inline Middleware with Lambda Expressions

The simplest approach uses `app.Use` with an inline lambda, which directly adds a delegate factory to the `_components` list:

```csharp
app.Use(async (context, next) =>
{
    // Pre-processing logic executes first
    Console.WriteLine($"Request: {context.Request.Path}");
    
    await next(); // Calls the next middleware in the chain
    
    // Post-processing logic executes on the return trip
    Console.WriteLine($"Response: {context.Response.StatusCode}");
});

```

This delegates directly to the `ApplicationBuilder.Use` method without requiring type activation.

### Typed Middleware Registration

For class-based middleware, the `UseMiddleware<T>()` extension method (defined in [`src/Http/Http.Abstractions/src/Extensions/UseMiddlewareExtensions.cs`](https://github.com/dotnet/aspnetcore/blob/main/src/Http/Http.Abstractions/src/Extensions/UseMiddlewareExtensions.cs)) handles type discovery and activation. When you call:

```csharp
app.UseMiddleware<MyLoggingMiddleware>();

```

The extension scans `MyLoggingMiddleware` for an `Invoke` or `InvokeAsync` method and validates its signature against the expected patterns.

## Middleware Activation and Dependency Injection

The [`UseMiddlewareExtensions.cs`](https://github.com/dotnet/aspnetcore/blob/main/UseMiddlewareExtensions.cs) file (lines 25-46) contains the binding logic that bridges the gap between your middleware class and the pipeline.

### Constructor Injection and Method Binding

When adding typed middleware, the framework performs the following steps:

1. **Constructor Analysis**: The middleware type is instantiated using the ASP.NET Core service provider, injecting constructor dependencies automatically.
2. **Method Discovery**: The binder inspects the type for `Task InvokeAsync(HttpContext)` or `Task Invoke(HttpContext)` methods.
3. **Delegate Compilation**: If the method accepts only `HttpContext`, it creates a direct delegate. For methods requiring additional services, it compiles an expression tree (or falls back to reflection) that resolves extra parameters from `HttpContext.RequestServices` at runtime.

```csharp
public class MyLoggingMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<MyLoggingMiddleware> _logger;

    public MyLoggingMiddleware(RequestDelegate next, ILogger<MyLoggingMiddleware> logger)
    {
        _next = next;
        _logger = logger;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        _logger.LogInformation("Handling request: {Path}", context.Request.Path);
        await _next(context);
        _logger.LogInformation("Finished handling request.");
    }
}

```

### The IMiddleware Alternative

For middleware requiring per-request activation from the dependency injection container, ASP.NET Core supports the `IMiddleware` interface (defined in [`src/Http/Http.Abstractions/src/IMiddleware.cs`](https://github.com/dotnet/aspnetcore/blob/main/src/Http/Http.Abstractions/src/IMiddleware.cs)). When using this pattern with `IMiddlewareFactory`, the middleware instance is resolved from DI for each request rather than being constructed as a singleton during pipeline building.

## Pipeline Termination and Unhandled Requests

When the pipeline reaches its end without a middleware short-circuiting the request, `ApplicationBuilder` provides a default terminal delegate. As implemented in [`ApplicationBuilder.cs`](https://github.com/dotnet/aspnetcore/blob/main/ApplicationBuilder.cs) (lines 84-92), this delegate sets the `__RequestUnhandled` item in the `HttpContext` dictionary to `true` and returns a 404 response:

```csharp
// From ApplicationBuilder.cs lines 84-92
if (app == null)
{
    return context =>
    {
        context.Response.StatusCode = 404;
        context.Items[RequestUnhandledKey] = true;
        return Task.CompletedTask;
    };
}

```

This flag allows higher-level frameworks like ASP.NET Core MVC to detect when no endpoint handled the request, enabling features like status code re-execution pages.

## Summary

- **`ApplicationBuilder`** stores middleware as `Func<RequestDelegate, RequestDelegate>` entries in an ordered list, with each entry representing a middleware factory that wraps the next component.
- **Reverse construction** during `Build()` (lines 164-200 in [`ApplicationBuilder.cs`](https://github.com/dotnet/aspnetcore/blob/main/ApplicationBuilder.cs)) ensures execution order matches registration order by wrapping delegates from the inside out.
- **Type activation** through [`UseMiddlewareExtensions.cs`](https://github.com/dotnet/aspnetcore/blob/main/UseMiddlewareExtensions.cs) handles constructor injection, `Invoke`/`InvokeAsync` method discovery, and expression tree compilation for service injection.
- **Unhandled requests** trigger a terminal delegate that sets `__RequestUnhandled` to `true` and returns HTTP 404, providing a hook for status code handling middleware.

## Frequently Asked Questions

### What is the difference between Use and UseMiddleware in ASP.NET Core?

**Use** accepts a lambda or delegate directly and adds it immediately to the `_components` list without type activation, while **UseMiddleware<T>** resolves the specified type from dependency injection, validates its `Invoke` method signature, and handles constructor parameter injection. Use `Use` for simple inline logic; use `UseMiddleware<T>` when you need dependency injection and reusable middleware classes.

### How does ASP.NET Core handle dependency injection in class-based middleware?

According to the [`UseMiddlewareExtensions.cs`](https://github.com/dotnet/aspnetcore/blob/main/UseMiddlewareExtensions.cs) implementation (lines 25-46), the framework first instantiates the middleware class using the service provider to satisfy constructor dependencies, then analyzes the `Invoke` or `InvokeAsync` method. If the method accepts parameters beyond `HttpContext`, the binder compiles an expression tree that resolves those additional services from `HttpContext.RequestServices` at runtime, avoiding reflection overhead in the hot path.

### Why is the middleware pipeline built in reverse order?

The `Build()` method in [`ApplicationBuilder.cs`](https://github.com/dotnet/aspnetcore/blob/main/ApplicationBuilder.cs) iterates backwards through the `_components` list (lines 164-200) so that the resulting `RequestDelegate` executes middleware in the same order it was registered. Because each middleware factory wraps the *next* delegate, starting from the end and working backwards creates a Russian doll structure where the first registered middleware becomes the outermost layer, intercepting requests first and finishing last during the response phase.

### What happens if no middleware handles the request?

If the pipeline reaches the terminal delegate without a middleware short-circuiting the request (by not calling `next()` or writing to the response), the `ApplicationBuilder` default delegate sets an internal flag `__RequestUnhandled` to `true` in the `HttpContext.Items` dictionary and returns HTTP 404 (lines 84-92 in [`ApplicationBuilder.cs`](https://github.com/dotnet/aspnetcore/blob/main/ApplicationBuilder.cs)). This allows framework components like endpoint routing to detect unhandled requests and execute status code pages or fallback endpoints.