Section 1 of 5

The Request Pipeline

🎯 What You'll Learn

  • What the request pipeline is
  • How HTTP requests flow through ASP.NET Core
  • Understanding middleware components
  • The pipeline execution model
  • Request and response flow
  • Short-circuiting the pipeline
  • Terminal vs non-terminal middleware
  • Visualizing the pipeline

What is the Request Pipeline?

The request pipeline is a series of components (called middleware) that handle HTTP requests and responses in ASP.NET Core.

πŸ’‘ Key Concept

Every HTTP request that comes into your application flows through the pipeline. Each middleware component can:

  • Process the request
  • Pass it to the next middleware
  • Process the response on the way back
  • Short-circuit (stop) the pipeline

How the Pipeline Works

Visual Flow Text
HTTP Request
    ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Middleware 1 (e.g., Logging)         β”‚ β†’ Request processing
β”‚    ↓                                  β”‚
β”‚  Middleware 2 (e.g., Authentication)  β”‚ β†’ Request processing
β”‚    ↓                                  β”‚
β”‚  Middleware 3 (e.g., Routing)         β”‚ β†’ Request processing
β”‚    ↓                                  β”‚
β”‚  Endpoint (Controller/Minimal API)    β”‚ β†’ Generate response
β”‚    ↓                                  β”‚
β”‚  Middleware 3                         β”‚ ← Response processing
β”‚    ↓                                  β”‚
β”‚  Middleware 2                         β”‚ ← Response processing
β”‚    ↓                                  β”‚
β”‚  Middleware 1                         β”‚ ← Response processing
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
    ↓
HTTP Response

The Flow

  1. Request comes in: HTTP request enters the pipeline
  2. Forward pass: Each middleware processes the request in order
  3. Endpoint: Final middleware generates a response
  4. Backward pass: Response flows back through middleware in reverse
  5. Response sent: HTTP response sent to client

Basic Pipeline Example

Program.cs C#
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

// Middleware 1: Logging
app.Use(async (context, next) =>
{
    Console.WriteLine("[1] Before next");
    await next(); // Call next middleware
    Console.WriteLine("[1] After next");
});

// Middleware 2: Authentication
app.Use(async (context, next) =>
{
    Console.WriteLine("[2] Before next");
    await next();
    Console.WriteLine("[2] After next");
});

// Middleware 3: Endpoint (Terminal)
app.Run(async context =>
{
    Console.WriteLine("[3] Handling request");
    await context.Response.WriteAsync("Hello World!");
});

app.Run();

Output

Console Output Text
[1] Before next
[2] Before next
[3] Handling request
[2] After next
[1] After next
πŸ’‘ Notice the Pattern

The request flows forward (1 β†’ 2 β†’ 3), then the response flows backward (3 β†’ 2 β†’ 1). This is the "onion" model.

Middleware Methods

1. app.Use() - Non-Terminal

app.Use() C#
app.Use(async (context, next) =>
{
    // Do something before
    await next(); // Call next middleware
    // Do something after
});

Use: Can call the next middleware. Non-terminal.

2. app.Run() - Terminal

app.Run() C#
app.Run(async context =>
{
    // Handle request - no next middleware
    await context.Response.WriteAsync("Done!");
});

Run: Terminal middleware. Ends the pipeline. No next parameter.

3. app.Map() - Branching

app.Map() C#
app.Map("/api", apiApp =>
{
    apiApp.Run(async context =>
    {
        await context.Response.WriteAsync("API endpoint");
    });
});

Map: Branch the pipeline based on request path.

4. app.MapWhen() - Conditional Branching

app.MapWhen() C#
app.MapWhen(
    context => context.Request.Query.ContainsKey("debug"),
    debugApp =>
    {
        debugApp.Run(async context =>
        {
            await context.Response.WriteAsync("Debug mode");
        });
    });

MapWhen: Branch based on a condition.

Short-Circuiting the Pipeline

Middleware can short-circuit by not calling next():

Short-Circuit Example C#
app.Use(async (context, next) =>
{
    if (!context.Request.Headers.ContainsKey("Authorization"))
    {
        // Short-circuit! Don't call next()
        context.Response.StatusCode = 401;
        await context.Response.WriteAsync("Unauthorized");
        return; // Stop here!
    }
    
    await next(); // Continue if authorized
});
⚠️ When to Short-Circuit

Short-circuit when:

  • Request is unauthorized
  • Request is invalid
  • Response can be served from cache
  • Static file can be served

HttpContext

Every middleware receives an HttpContext object that contains:

Property Description
Request HTTP request details (headers, body, query, etc.)
Response HTTP response to send back
User Authenticated user information
Items Per-request data storage
RequestServices DI service provider (scoped)
Session User session data
Using HttpContext C#
app.Use(async (context, next) =>
{
    // Read request
    var path = context.Request.Path;
    var method = context.Request.Method;
    
    // Store data for later middleware
    context.Items["RequestTime"] = DateTime.UtcNow;
    
    await next();
    
    // Modify response
    context.Response.Headers["X-Custom-Header"] = "InvenTrack";
});

Complete InvenTrack Example

Program.cs (InvenTrack Pipeline) C#
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();

var app = builder.Build();

// 1. Request logging
app.Use(async (context, next) =>
{
    var start = DateTime.UtcNow;
    Console.WriteLine($"β†’ {context.Request.Method} {context.Request.Path}");
    
    await next();
    
    var duration = (DateTime.UtcNow - start).TotalMilliseconds;
    Console.WriteLine($"← {context.Response.StatusCode} ({duration:F2}ms)");
});

// 2. CORS
app.UseCors();

// 3. Authentication
app.UseAuthentication();

// 4. Authorization
app.UseAuthorization();

// 5. Routing & Endpoints
app.MapControllers();

app.Run();

Key Takeaways

  • The request pipeline is a series of middleware components
  • Requests flow forward, responses flow backward
  • app.Use() is non-terminal (calls next middleware)
  • app.Run() is terminal (ends the pipeline)
  • app.Map() branches the pipeline by path
  • app.MapWhen() branches by condition
  • Middleware can short-circuit by not calling next()
  • HttpContext contains request and response details
  • Middleware order matters (covered in Section 4)
  • Each middleware can process both request and response
🎯 Next Steps

You now understand how the request pipeline works! In the next section, we'll explore Built-in Middlewareβ€”the middleware components that ASP.NET Core provides out of the box for common tasks like authentication, CORS, static files, and more.