# How ASP.NET Core Processes Incoming HTTP Requests: Pipeline Architecture Explained

> Understand how ASP.NET Core processes incoming HTTP requests using its middleware pipeline architecture. Learn how requests are handled sequentially to generate responses efficiently.

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

---

**ASP.NET Core processes every incoming HTTP request through a composable middleware pipeline that compiles into a single `RequestDelegate`, which receives an `HttpContext` and executes registered components sequentially until a response is generated or a 404 is returned.**

The `dotnet/aspnetcore` repository implements a flexible, high-performance request processing architecture that transforms incoming HTTP traffic into executable code. Understanding how ASP.NET Core processes incoming HTTP requests requires examining the middleware pipeline construction, the `RequestDelegate` compilation, and the role of `HttpContext` in state management.

## The Pipeline Foundation: HttpContext and ApplicationBuilder

Every request begins with two core abstractions defined in the `src/Http/Http.Abstractions/src/` directory.

### HttpContext: The Request State Container

The **`HttpContext`** class, located in [[`HttpContext.cs`](https://github.com/dotnet/aspnetcore/blob/main/HttpContext.cs)](https://github.com/dotnet/aspnetcore/blob/main/src/Http/Http.Abstractions/src/HttpContext.cs), encapsulates all HTTP-specific information for a single request. It holds the `HttpRequest`, `HttpResponse`, and feature collections that middleware components read and modify throughout the pipeline.

### IApplicationBuilder: Pipeline Configuration

The pipeline is configured through **`IApplicationBuilder`**, defined in [[`IApplicationBuilder.cs`](https://github.com/dotnet/aspnetcore/blob/main/IApplicationBuilder.cs)](https://github.com/dotnet/aspnetcore/blob/main/src/Http/Http.Abstractions/src/IApplicationBuilder.cs). The concrete implementation, **`ApplicationBuilder`** in [[`src/Http/Http/src/Builder/ApplicationBuilder.cs`](https://github.com/dotnet/aspnetcore/blob/main/src/Http/Http/src/Builder/ApplicationBuilder.cs)](https://github.com/dotnet/aspnetcore/blob/main/src/Http/Http/src/Builder/ApplicationBuilder.cs), maintains a list of middleware components registered via `Use()` and `Run()` methods.

## Building the Request Pipeline

When the application starts, the middleware list compiles into an executable chain.

### From Middleware to RequestDelegate

The **`ApplicationBuilder.Build()`** method transforms the registered middleware into a single **`RequestDelegate`**, defined in [[`RequestDelegate.cs`](https://github.com/dotnet/aspnetcore/blob/main/RequestDelegate.cs)](https://github.com/dotnet/aspnetcore/blob/main/src/Http/Http.Abstractions/src/RequestDelegate.cs). This delegate accepts an `HttpContext` and returns a `Task`, representing the entry point for every request.

If no middleware handles the request, `Build()` supplies a fallback delegate that sets `StatusCodes.Status404NotFound` and marks the request as unhandled.

## Middleware Execution Flow

When a request arrives, the server invokes the compiled `RequestDelegate` with a newly created `HttpContext`.

### The Middleware Chain

Each middleware component receives the context and a **`RequestDelegate next`** parameter representing the remainder of the pipeline. Middleware can:

- Read `HttpContext.Request` properties
- Write to `HttpContext.Response` 
- Store data in `HttpContext.Items`
- **Short-circuit** the pipeline by not calling `await next(context)`
- Pass control forward with `await next(context)`

The chain executes in registration order during the request phase, then reverses for the response phase as the stack unwinds.

## Endpoint Routing Integration

Modern ASP.NET Core applications typically integrate endpoint routing into the middleware pipeline.

### The Routing Middleware

The [[`EndpointRoutingApplicationBuilderExtensions.cs`](https://github.com/dotnet/aspnetcore/blob/main/EndpointRoutingApplicationBuilderExtensions.cs)](https://github.com/dotnet/aspnetcore/blob/main/src/Http/Routing/src/Builder/EndpointRoutingApplicationBuilderExtensions.cs) provides `UseRouting()` and `UseEndpoints()` methods that insert routing middleware into the pipeline. When `UseRouting()` executes, it matches the request to an **`Endpoint`** and stores the endpoint's `RequestDelegate` on the `HttpContext`.

If the pipeline reaches its end without executing the matched endpoint, `ApplicationBuilder.Build()` throws an `InvalidOperationException` with a clear diagnostic message indicating that the endpoint was never invoked.

## Practical Implementation Examples

### Minimal API Configuration

In Minimal APIs, the `WebApplication` automatically constructs the pipeline:

```csharp
var app = WebApplication.CreateBuilder(args).Build();

app.MapGet("/", () => "Hello, world!");   // registers endpoint middleware
app.Run();                                 // starts the server

```

### Custom Middleware Implementation

Class-based middleware implements `IMiddleware` from [[`IMiddleware.cs`](https://github.com/dotnet/aspnetcore/blob/main/IMiddleware.cs)](https://github.com/dotnet/aspnetcore/blob/main/src/Http/Http.Abstractions/src/IMiddleware.cs):

```csharp
public class LoggingMiddleware : IMiddleware
{
    public async Task InvokeAsync(HttpContext context, RequestDelegate next)
    {
        Console.WriteLine($"{context.Request.Method} {context.Request.Path}");
        await next(context);                 // invoke next middleware
    }
}

// Registration
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddTransient<LoggingMiddleware>();
var app = builder.Build();

app.UseMiddleware<LoggingMiddleware>();     // adds to the pipeline
app.MapGet("/", () => "OK");
app.Run();

```

### Explicit Pipeline Construction

For advanced scenarios, manually construct the pipeline using `ApplicationBuilder`:

```csharp
var app = new ApplicationBuilder(serviceProvider);

app.Use(async (ctx, next) =>
{
    // first middleware
    ctx.Response.Headers.Add("X-First", "true");
    await next(ctx);
});

app.Use(async (ctx, next) =>
{
    // second middleware
    ctx.Response.Headers.Add("X-Second", "true");
    await next(ctx);
});

app.UseEndpoints(endpoints =>
{
    endpoints.MapGet("/", async ctx => await ctx.Response.WriteAsync("Done"));
});

var requestDelegate = app.Build();   // compiles the pipeline
// The server will invoke `requestDelegate(context)` for each request.

```

## Summary

- **ASP.NET Core compiles middleware registrations** into a single `RequestDelegate` via `ApplicationBuilder.Build()`, creating a high-performance execution pipeline.
- **Each request receives an `HttpContext`** instance that flows through the middleware chain, allowing components to inspect and modify request and response data.
- **Middleware components call `await next(context)`** to pass control down the pipeline, enabling both pre-processing and post-processing logic as the call stack unwinds.
- **Endpoint routing integrates** via `UseRouting()` and `UseEndpoints()`, throwing an `InvalidOperationException` if a matched endpoint is never executed.
- **Unhandled requests return 404** through a fallback delegate automatically added when `Build()` compiles the pipeline.

## Frequently Asked Questions

### What is the difference between `IApplicationBuilder` and `ApplicationBuilder`?

**`IApplicationBuilder`** is the abstraction defined in [`IApplicationBuilder.cs`](https://github.com/dotnet/aspnetcore/blob/main/IApplicationBuilder.cs) that specifies the contract for registering middleware, while **`ApplicationBuilder`** is the concrete implementation in [`src/Http/Http/src/Builder/ApplicationBuilder.cs`](https://github.com/dotnet/aspnetcore/blob/main/src/Http/Http/src/Builder/ApplicationBuilder.cs) that actually stores the middleware list and compiles it into a `RequestDelegate` via the `Build()` method.

### How does ASP.NET Core handle requests that don't match any endpoints?

When the middleware pipeline completes without a component writing a response or short-circuiting, the compiled `RequestDelegate` invokes a terminal fallback that sets the response status code to `404 Not Found`. This ensures every request receives a deterministic response even when no middleware handles it.

### Can middleware modify the response after calling `next(context)`?

Yes. Because the `RequestDelegate` chain uses the C# call stack, code executing after `await next(context)` runs during the response phase as the stack unwinds. Middleware can modify response headers or even replace the response body at this stage, provided the response has not started streaming to the client.

### What happens if a middleware throws an exception?

If a middleware throws an exception before calling `next(context)`, the pipeline short-circuits immediately and the exception propagates back up the call stack. The server or exception handling middleware (such as `DeveloperExceptionPageMiddleware` or `ExceptionHandlerMiddleware`) catches this and generates an appropriate error response.