ASP.NET Core  

What Are Middleware Components in ASP.NET Core and How Do They Work?

Introduction

Middleware components are one of the most important concepts in ASP.NET Core Web API development. They control how requests and responses flow through your application.

If you understand middleware properly, you can build powerful features like authentication, logging, exception handling, routing, and much more.

In this article, you will learn what middleware is, how it works internally, and how to create your own middleware step by step using simple language and real examples.

What is Middleware in ASP.NET Core?

Middleware is a piece of code that handles HTTP requests and responses.

It sits in the request pipeline and decides:

  • Whether to process the request

  • Whether to pass it to the next component

  • Whether to stop the request

In simple words:

Middleware = Request + Processing + Response

Understanding the Request Pipeline

ASP.NET Core uses a pipeline where multiple middleware components are executed in sequence.

Flow:

  • Request comes from client

  • Passes through multiple middleware

  • Each middleware can modify request/response

  • Finally reaches endpoint (controller)

  • Response travels back through same middleware

Example flow:

Client → Middleware 1 → Middleware 2 → Middleware 3 → Controller → Response → Middleware 3 → Middleware 2 → Middleware 1 → Client

This is also called a "chain of responsibility" pattern.

How Middleware Works Internally

Each middleware has access to:

  • HttpContext (request + response data)

  • Next delegate (next middleware in pipeline)

Basic structure:

public async Task InvokeAsync(HttpContext context)
{
    // Before next middleware

    await _next(context);

    // After next middleware
}

Key idea:

  • Code before _next → runs on request

  • Code after _next → runs on response

Built-in Middleware in ASP.NET Core

ASP.NET Core provides many built-in middleware components:

  • UseRouting → Matches request to endpoints

  • UseAuthentication → Validates user identity

  • UseAuthorization → Checks permissions

  • UseStaticFiles → Serves static content

  • UseExceptionHandler → Handles global exceptions

  • UseHttpsRedirection → Redirects HTTP to HTTPS

Example configuration:

app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.UseRouting();
app.MapControllers();

Order matters here. Changing order can break your application.

Why Middleware Order is Important

Middleware executes in the order it is added.

Example:

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

If reversed:

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

Authorization will fail because user is not authenticated yet.

So always maintain correct order.

Types of Middleware

There are three common ways to create middleware:

1. Inline Middleware

Defined directly in Program.cs

app.Use(async (context, next) =>
{
    Console.WriteLine("Request started");

    await next();

    Console.WriteLine("Response finished");
});

2. Convention-based Middleware

Custom class with Invoke or InvokeAsync method

public class LoggingMiddleware
{
    private readonly RequestDelegate _next;

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

    public async Task InvokeAsync(HttpContext context)
    {
        Console.WriteLine("Request incoming");

        await _next(context);

        Console.WriteLine("Response outgoing");
    }
}

Register it:

app.UseMiddleware<LoggingMiddleware>();

3. Factory-based Middleware

Uses IMiddleware interface (less common but useful with DI)

public class CustomMiddleware : IMiddleware
{
    public async Task InvokeAsync(HttpContext context, RequestDelegate next)
    {
        await next(context);
    }
}

Register:

builder.Services.AddTransient<CustomMiddleware>();
app.UseMiddleware<CustomMiddleware>();

Creating Custom Middleware Step by Step

Let’s create a simple request logging middleware.

Step 1: Create Middleware Class

public class RequestLoggingMiddleware
{
    private readonly RequestDelegate _next;

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

    public async Task InvokeAsync(HttpContext context)
    {
        Console.WriteLine($"Request: {context.Request.Method} {context.Request.Path}");

        await _next(context);

        Console.WriteLine($"Response Status: {context.Response.StatusCode}");
    }
}

Step 2: Register Middleware

app.UseMiddleware<RequestLoggingMiddleware>();

Step 3: Test

Run API and hit any endpoint. You will see logs in console.

Short-Circuiting Middleware

Middleware can stop request pipeline.

Example:

app.Use(async (context, next) =>
{
    if (!context.Request.Headers.ContainsKey("Authorization"))
    {
        context.Response.StatusCode = 401;
        await context.Response.WriteAsync("Unauthorized");
        return;
    }

    await next();
});

Here request stops if header is missing.

Middleware vs Filters in ASP.NET Core

FeatureMiddlewareFilters
ScopeGlobalMVC only
ExecutionBefore MVCInside MVC
Use caseLogging, AuthAction-specific logic

Real-World Use Cases of Middleware

Middleware is used in:

  • Authentication & Authorization

  • Logging & Monitoring

  • Error Handling

  • Request/Response modification

  • Rate limiting

Best Practices for Middleware

  • Keep middleware small and focused

  • Maintain correct order

  • Avoid heavy processing

  • Use async methods

  • Log important information

Common Mistakes to Avoid

  • Incorrect middleware order

  • Not calling next()

  • Blocking async code

  • Writing too much logic in one middleware

Summary

Middleware in ASP.NET Core is a powerful concept that controls how HTTP requests and responses are handled. By understanding the request pipeline, middleware order, and how to build custom middleware, you can create scalable and maintainable web applications. Proper use of middleware improves performance, security, and overall application design.