.NET Core  

Mastering Middleware in ASP.NET Core: The Complete Guide to Request Pipeline

Introduction

Middleware and the Request Pipeline are essential building blocks of ASP.NET Core that allow developers to control how HTTP requests and responses are handled within an application.

In this article, we’ll break down what middleware is and how the request pipeline works. Additionally, we’ll share a handy interview cheat sheet to boost your confidence during technical interviews.

What You’ll Learn in this article

  • The core concept of middleware and the request pipeline

  • The lifecycle of an HTTP request in ASP.NET Core

  • The use of app.Use, app.Run, and app.Map

  • Built-in middleware components like static files, routing, authentication,  Middleware ordering, and execution flow

  • How to write custom middleware with RequestDelegate and HttpContext

  • Difference between middleware and filters

  • Common interview questions and answers

What is Middleware?

In ASP.NET Core, middleware is a software component that is assembled into the application pipeline to handle HTTP requests and responses. Each middleware has the ability to:

  • Inspect the incoming request

  • Take action (e.g., logging, authentication)

  • Modify the request or response

  • Decide whether to pass the request to the next middleware or stop processing.

Middleware is added to the application in a specific order, and this order defines the flow of the HTTP request through the application.

What is the Request Pipeline?

The Request Pipeline is the sequence of middleware components that an HTTP request passes through on its way to a response. When a request hits the application:

  1. Request enters the request pipeline.

  2. Each middleware has a chance to:

    • Do something before passing it to the next component.

    • Do something after the next component has processed it.

  3. The last component generates a response, which then flows back through the pipeline in reverse order.

How does it work?

  • Request enters the pipeline.

  • It goes through each middleware component in the order in which they are registered.

  • Each middleware can:

    • Do something before passing the request to the next middleware.

    • Do something after the next middleware has processed the request (usually on the response).

    • Short-circuit the pipeline by not calling the next middleware.

  • Finally, the response flows back through the pipeline.

Request  →  Middleware1  →  Middleware2  →  Middleware3  →  Endpoint
                             ↑                             ↑                          ↑                             ↓
               Do Something                Do Something    Do Something     Generate response

Real-world scenario

Think of middleware as a series of layers in an onion. The HTTP request passes through each layer going in (toward the core), and the response comes back out through those same layers.

Lifecycle of an HTTP request

The lifecycle of an HTTP request in ASP.NET Core is a structured flow that begins when a request is received by the server and ends when the response is sent back to the client. Understanding this lifecycle helps you write better middleware, manage performance, and debug effectively.

Step-by-Step Lifecycle

1. Request Received by Kestrel

  • Kestrel is ASP.NET Core's cross-platform web server.

  • It handles the low-level HTTP protocol and listens for requests.

2. Passed to Middleware Pipeline

  • ASP.NET Core uses a middleware-based pipeline.

  • Each middleware has a chance to:

    • Inspect or modify the request

    • Pass it to the next middleware (await _next(context))

    • Stop the pipeline and return a response directly

3. Routing Middleware (app.UseRouting())

  • Parses the URL and determines which endpoint (controller, Razor Page, or minimal API) to use.

4. Authentication & Authorization (if configured)

  • Middleware like UseAuthentication() and UseAuthorization() validate credentials and permissions.

5. Endpoint Execution

  • Executes the matched endpoint handler:

    • Controller Action (MVC/Web API)

    • Razor Page Handler

    • Minimal API method

    • SignalR hub method

  • This is where your app logic runs (database queries, business logic, etc.)

6. Response Travels Back Through Middleware

  • After the endpoint is processed, the response is sent back through the pipeline.

  • Middleware can now modify or log the response (e.g., logging, compression, headers).

7. Kestrel Sends Response to Client

  • The final HTTP response is sent back over the network to the client (browser, app, etc.)

Client
  ↓
Kestrel Web Server
  ↓
Middleware Pipeline (UseMiddleware)
  ↓
Routing Middleware
  ↓
Endpoint Execution (Controller / Razor / Minimal API)
  ↓
Middleware Pipeline (Response flows back)
  ↓
Kestrel sends response
  ↓
Client
Lifecycle of an HTTP request
Component Role
Kestrel Handles HTTP connection
Middleware pipeline Adds cross-cutting behavior (logging, auth, etc.)
Routing Matches incoming request to endpoint
Endpoint execution Runs controller, Razor page, or API logic
Response middleware Can modify/log response before it leaves the server
Kestrel sends response Final response goes back to the client

app.UseMiddleware with next delegate

Adds middleware to the pipeline that will run for every request.

It doesn’t end the request instead, it passes control to the next middleware using await next.Invoke().

// Use Middleware: This runs for all requests
app.Use(async (context, next) =>
{
    // Do something before
    await next.Invoke(); // Call the next middleware
    // Do something after
});

app.Map – Branching middleware

Used to branch the pipeline based on request paths.

This middleware will only be executed if the request path matches the specified path.

app.Map("/about", appBuilder =>
{
    appBuilder.Run(async context =>
    {
        await context.Response.WriteAsync("About Page");
    });
});

app.Run – Terminal middleware

This middleware will always execute if no previous middleware short-circuits the pipeline and does not call any next middleware.

It is typically used at the end of the pipeline to generate a final response and stop further processing.

app.Run(async context =>
{
    await context.Response.WriteAsync("Hello from app.Run!");
});

Built-in middleware components in Asp.NET Core

Middleware components are pieces of code that are assembled into an application pipeline to handle requests and responses. ASP.NET Core provides several built-in middleware components to support common scenarios such as serving static files, handling authentication, routing requests, and more.

Middleware Description
Static Files (UseStaticFiles) Serves static files like HTML, CSS, JS, images, etc., from the wwwroot folder.
Routing (UseRouting) Matches the incoming HTTP requests to endpoints defined in the app. Required for endpoint routing.
Endpoints (UseEndpoints) Executes the matched endpoint (e.g., controller action, Razor Page, minimal API).
Authentication (UseAuthentication) Enables authentication logic (e.g., JWT, cookies, identity). Should be placed before authorization.
Authorization (UseAuthorization) Validates that the user is authorized to access certain resources.
CORS (UseCors) Enables Cross-Origin Resource Sharing (CORS) support to allow or restrict cross-origin requests.
Exception Handling (UseExceptionHandler, UseDeveloperExceptionPage) Handles exceptions globally and provides error responses. Dev page shows detailed errors.
HTTPS Redirection (UseHttpsRedirection) Redirects all HTTP requests to HTTPS.
Session (UseSession) Enables session state in web apps. Requires session services configuration.
Cookie Policy (UseCookiePolicy) Enables GDPR-compliant cookie handling, like consent checks.
WebSockets (UseWebSockets) Enables WebSocket support for real-time communication.
Response Caching (UseResponseCaching) Caches HTTP responses to improve performance.

Middleware Pipeline in Program.cs

var builder = WebApplication.CreateBuilder(args);

// Add services
builder.Services.AddRouting();
builder.Services.AddAuthentication();
builder.Services.AddAuthorization();
builder.Services.AddControllersWithViews();

var app = builder.Build();

// Middleware pipeline
app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
});

app.Run();

Key Points

The order in which middleware components are added is critical. For example:

  • UseRouting() → before UseAuthorization()

  • UseAuthentication() → before UseAuthorization()

  • UseStaticFiles() → before routing so static content is served without hitting the MVC pipeline.

Custom Middleware

Creating custom middleware in ASP.NET Core allows you to insert your own logic into the HTTP request pipeline. This is useful for tasks like logging, custom authentication, modifying responses, or intercepting requests.

Step-by-step

  1. Create the Middleware Class

  2. Create an Extension Method

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;
using System;

public class RequestLoggingMiddleware
{
    private readonly RequestDelegate _next;

    public RequestLoggingMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    // Middleware logic
    public async Task InvokeAsync(HttpContext context)
    {
        // Log the incoming request
        Console.WriteLine($"[Request] {context.Request.Method} {context.Request.Path}");

        await _next(context); // Call the next middleware

        // Log the outgoing response
        Console.WriteLine($"[Response] {context.Response.StatusCode}");
    }
}

// Extension method for clean registration
public static class RequestLoggingMiddlewareExtensions
{
    public static IApplicationBuilder UseRequestLogging(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<RequestLoggingMiddleware>();
    }
}
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.UseHttpsRedirection();

// Register your custom middleware
app.UseMiddleware<RequestLoggingMiddleware>();

app.UseRouting();
app.UseAuthorization();

app.MapControllers();

app.Run();

Here are common interview questions and answers based on the topic “Mastering Middleware in ASP.NET Core: The Complete Guide to Request Pipeline”, suitable for .NET developer interviews:

🔹1. What is middleware in ASP.NET Core?

Answer

Middleware is software that's assembled into an application pipeline to handle requests and responses. Each component in the pipeline can either:

  • Handle the request completely, or

  • Pass it to the next middleware using await next().

🔹 2. How is middleware registered in the request pipeline?

Answer

Middleware is registered in the Program.cs or Startup.cs using extension methods like app.Use, app.Run, and app.Map.

Example

app.UseMiddleware<CustomMiddleware>();

🔹 3. What's the difference between app.Use, app.Run, and app.Map?

Method Description
Use Adds middleware that can call the next component.
Run Terminates the pipeline; no further middleware is invoked.
Map Branches the pipeline based on request path.

Common interview questions and answers

1. What is middleware in ASP.NET Core?

Answer

Middleware is software that's assembled into an application pipeline to handle requests and responses. Each component in the pipeline can either:

  • Handle the request completely, or

  • Pass it to the next middleware using await next().

2. How is middleware registered in the request pipeline?

Answer

Middleware is registered in the Program.cs or Startup.cs using extension methods like app.Use, app.Run, and app.Map.

app.UseMiddleware<CustomMiddleware>();

3. What's the difference between app.Use, app.Run, and app.Map?

Method Description
Use Adds middleware that can call the next component.
Run Terminates the pipeline, no further middleware is invoked.
Map Branches the pipeline based on request path.

4. Explain the order of middleware execution. Why is it important?

Middleware executes in the order it's registered. The order matters because:

  • Early middleware (like logging, exception handling) can wrap later middleware.

  • Authentication should be registered before authorization.

  • app.UseRouting() should come before app.UseAuthorization().

5. How do you write a custom middleware in ASP.NET Core?

public class CustomMiddleware
{
    private readonly RequestDelegate _next;
    public CustomMiddleware(RequestDelegate next) => _next = next;

    public async Task InvokeAsync(HttpContext context)
    {
        // Pre-processing logic
        await _next(context); // Call next middleware
        // Post-processing logic
    }
}

Register it using

app.UseMiddleware<CustomMiddleware>();

6. What is the role of RequestDelegate in middleware?

RequestDelegate represents the next middleware in the pipeline. It is used to invoke the next component using:

await _next(context);

7. How do you implement global exception handling using middleware?

Create a middleware that wraps the pipeline in a try-catch block and returns a custom response on error.

Example

public class ExceptionMiddleware
{
    private readonly RequestDelegate _next;
    public ExceptionMiddleware(RequestDelegate next) => _next = next;

    public async Task InvokeAsync(HttpContext context)
    {
        try
        {
            await _next(context);
        }
        catch (Exception ex)
        {
            // Log and handle error
            context.Response.StatusCode = 500;
            await context.Response.WriteAsync("Internal Server Error");
        }
    }
}

8. What are terminal and non-terminal middleware?

  • Terminal Middleware: Ends the request pipeline (e.g., app.Run(...))

  • Non-terminal Middleware: Calls await next() to pass control to the next middleware (e.g., app.Use(...))

9. How does middleware support dependency injection?

You can inject services into middleware through the constructor.

Example

public class LoggingMiddleware
{
    private readonly ILogger<LoggingMiddleware> _logger;
    public LoggingMiddleware(RequestDelegate next, ILogger<LoggingMiddleware> logger)
    {
        _logger = logger;
    }
}

10. Can you explain a real-time scenario where middleware is useful?

  • Authentication Middleware is used to validate tokens before requests reach controllers.
  • Logging Middleware can log every incoming request and outgoing response for audit and debugging.

Middleware – Summary Notes

  • Definition: Middleware is a component in the HTTP request pipeline that can inspect, modify, or terminate HTTP requests and responses during processing.

  • Execution: Executes for every HTTP request, regardless of whether the target is MVC, Razor Pages, static files, or others.

  • Placement: Middleware is configured in Startup.cs or Program.cs using methods like:

    • app.Use(...) – to call the next middleware in the pipeline

    • app.Run(...) – to end the pipeline

    • app.Map(...) – to branch the pipeline based on request path

  • Use Cases

    • Logging

    • Authentication & Authorization

    • CORS (Cross-Origin Resource Sharing)

    • Exception Handling

    • Response Compression

    • Localization

    • Request/Response Inspection

    • Request Redirection and Modification

  • Granularity: Middleware works at a global application level, affecting all incoming and outgoing requests.

Conclusion

Middleware plays a critical role in handling cross-cutting concerns across the application in a centralized and consistent way. It enables developers to build reusable, modular components that simplify request/response processing.

Mastering how and when to use middleware is essential for building robust, scalable, and maintainable ASP.NET Core applications. By strategically placing and organizing middleware, you can ensure better performance, cleaner code architecture, and improved application security.

Thank you for taking the time to read this post. I hope it has provided you with a clear understanding of middleware in ASP.NET Core and empowered you to apply it effectively in real-world applications.

Keep learning, keep experimenting, and keep building robust and scalable web solutions with confidence.