Middleware in ASP.NET Core: A Comprehensive Guide

Middleware is a core feature of ASP.NET Core that processes HTTP requests and responses in the request/response pipeline. It enables cross-cutting concerns like logging, authentication, error handling, and more. Learn how middleware works, its types, how to create custom middleware, and best practices for implementing it in your ASP.NET Core applications.

By Ajith joseph · Mon Mar 24 2025 · Updated Mon Mar 24 2025 · 11 min read · intermediate

#dotnet #csharp #api #security

Middleware is a cornerstone of ASP.NET Core, enabling developers to process HTTP requests and responses in a modular and reusable way. It acts as a bridge between the incoming request and the outgoing response, allowing you to implement cross-cutting concerns such as logging, authentication, error handling, and more. Middleware is a key part of the ASP.NET Core request/response pipeline, and understanding it is essential for building robust and scalable web applications.

This document provides a detailed explanation of middleware in ASP.NET Core, including its purpose, how it works, types of middleware, how to create and use custom middleware, and best practices.


What is Middleware?

Middleware in ASP.NET Core is a piece of software that processes HTTP requests and responses. It is executed during the request/response lifecycle of an HTTP request and can:

  • Modify the incoming request.
  • Perform operations such as logging, authentication, or error handling.
  • Modify the outgoing response.
  • Terminate the pipeline and send a response back to the client.

Middleware is essentially a function that:

  1. Reads the incoming HTTP request.
  2. Performs some processing (e.g., logging, authentication, etc.).
  3. Either:
    • Passes the request to the next middleware in the pipeline.
    • Terminates the pipeline and sends a response back to the client.

Why Use Middleware?

Middleware is used to implement cross-cutting concerns—functionality that applies to multiple parts of an application. Instead of scattering this functionality across controllers or other parts of the application, middleware centralizes it, making the application more modular, maintainable, and testable.

Common Use Cases for Middleware:

  • Logging: Recording incoming requests and outgoing responses for debugging and monitoring.
  • Authentication: Verifying user identity before allowing access to resources.
  • Authorization: Enforcing access control based on roles or policies.
  • Error Handling: Catching and handling exceptions globally.
  • Static File Serving: Serving static files like CSS, JavaScript, and images.
  • CORS (Cross-Origin Resource Sharing): Managing cross-origin requests.
  • Compression: Compressing responses (e.g., gzip or Brotli) to improve performance.
  • Custom Headers: Adding custom headers to requests or responses.

How Middleware Works in ASP.NET Core

In ASP.NET Core, middleware is organized into a request/response pipeline. When an HTTP request is received, it passes through the middleware pipeline, where each middleware component processes the request and either:

  1. Passes the request to the next middleware in the pipeline.
  2. Terminates the pipeline and sends a response back to the client.

Middleware Pipeline Execution

  • Middleware components are added to the pipeline in the Startup.cs file (or Program.cs in .NET 6+).
  • Each middleware component can modify the request or response as it passes through the pipeline.
  • The pipeline can be configured to handle specific routes, status codes, or conditions.

Middleware Execution Flow

  1. A request is received by the server.
  2. The request enters the middleware pipeline.
  3. Each middleware processes the request and calls the next middleware in the pipeline (if applicable).
  4. If a middleware terminates the pipeline, it sends a response back to the client.
  5. If no middleware terminates the pipeline, the response is sent back after all middleware has been executed.

Types of Middleware

Middleware in ASP.NET Core can be categorized into two types:

1. Framework-Provided Middleware

ASP.NET Core includes built-in middleware for common tasks such as logging, routing, authentication, and error handling. These are pre-built and ready to use.

Examples of Framework-Provided Middleware:

  • Logging Middleware: Logs incoming requests and responses.
  • Routing Middleware: Maps incoming requests to controller actions.
  • Authentication Middleware: Handles user authentication.
  • Authorization Middleware: Enforces access control based on roles or policies.
  • Static File Middleware: Serves static files like CSS, JavaScript, and images.
  • Error Handling Middleware: Handles exceptions and returns appropriate error responses.

Example: Using Built-in Middleware

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage(); // Error handling middleware
    }

    app.UseRouting(); // Routing middleware
    app.UseAuthentication(); // Authentication middleware
    app.UseAuthorization(); // Authorization middleware

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers(); // Maps API routes
    });
}

2. Custom Middleware

Developers can create their own middleware to handle specific requirements that are not covered by the built-in middleware. Custom middleware is typically implemented as a class or a delegate.

Example: Custom Middleware

public class CustomMiddleware
{
    private readonly RequestDelegate _next;

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

    public async Task InvokeAsync(HttpContext context)
    {
        // Perform some processing before passing the request to the next middleware
        Console.WriteLine("Custom Middleware: Processing request...");

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

        // Perform some processing after the response is sent
        Console.WriteLine("Custom Middleware: Processing response...");
    }
}

To use the custom middleware, you need to register it in the Configure method (or Program.cs in .NET 6+):

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseMiddleware<CustomMiddleware>();

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

Creating Middleware in ASP.NET Core

To create middleware in ASP.NET Core, you typically follow these steps:

Step 1: Create a Middleware Class

The middleware class should implement a method (InvokeAsync) that processes the request and optionally calls the next middleware.

public class LoggingMiddleware
{
    private readonly RequestDelegate _next;

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

    public async Task InvokeAsync(HttpContext context)
    {
        // Log the incoming request
        Console.WriteLine(
quot;Incoming Request: {context.Request.Method} {context.Request.Path}"); // Call the next middleware in the pipeline await _next(context); // Log the outgoing response Console.WriteLine(
quot;Outgoing Response: {context.Response.StatusCode}"); } }

Step 2: Create a Middleware Extension Method

To make the middleware easier to use, create an extension method for IApplicationBuilder.

public static class LoggingMiddlewareExtensions
{
    public static IApplicationBuilder UseLoggingMiddleware(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<LoggingMiddleware>();
    }
}

Step 3: Register the Middleware

Register the middleware in the Configure method (or Program.cs in .NET 6+).

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseLoggingMiddleware(); // Register custom middleware
    app.UseRouting();
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}

Middleware in .NET 6 and Later (Minimal API)

In .NET 6 and later, the introduction of minimal APIs simplifies the process of creating and configuring middleware. Middleware can now be registered directly in the Program.cs file without requiring a separate Startup.cs file.

Example: Minimal API Middleware

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

// Add middleware directly in Program.cs
app.Use(async (context, next) =>
{
    Console.WriteLine("Processing request...");
    await next(context); // Call the next middleware
    Console.WriteLine("Processing response...");
});

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

app.Run();

Order of Middleware Execution

The order in which middleware is registered determines the order in which it is executed. Middleware is executed in the following sequence:

  1. Middleware registered first is executed first.
  2. Middleware can terminate the pipeline, preventing subsequent middleware from being executed.

Example:

app.Use(async (context, next) =>
{
    Console.WriteLine("Middleware 1: Before Next");
    await next(context);
    Console.WriteLine("Middleware 1: After Next");
});

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

Output (if no middleware terminates the pipeline):

Middleware 1: Before Next
Middleware 2: Before Next
Middleware 2: After Next
Middleware 1: After Next

Best Practices for Using Middleware

  1. Keep Middleware Focused: Each middleware should have a single responsibility. Avoid combining multiple concerns into one middleware.
  2. Use Extension Methods: Create extension methods for custom middleware to make it easier to register and reuse.
  3. Order Matters: Middleware is executed in the order it is registered. Ensure that middleware is registered in the correct order (e.g., authentication before authorization).
  4. Avoid Overhead: Minimize the processing time of middleware to avoid impacting application performance.
  5. Test Middleware: Write unit tests for custom middleware to ensure it behaves as expected.
  6. Use Conditional Middleware: Use conditional logic to register middleware only when needed (e.g., environment-specific middleware).

Middleware is a powerful feature in ASP.NET Core that allows developers to process HTTP requests and responses in a modular and reusable way. It is used to implement cross-cutting concerns such as logging, authentication, error handling, and more. By understanding how middleware works, creating custom middleware, and following best practices, developers can build robust, maintainable, and scalable web applications.

Whether you're using built-in middleware or creating your own, middleware is an essential tool for managing the request/response pipeline in ASP.NET Core. With its flexibility and simplicity, middleware empowers developers to create high-performance web applications with ease.

  1. AJ's Tech Notes
  2. Middleware in ASP.NET Core: A Comprehensive Guide