ASP.NET Core 8 middleware request pipeline diagram with authentication, custom middleware, logging, and endpoint flow

What Is Middleware in ASP.NET Core 8? Request Pipeline Explained with Custom Middleware Example

What Is Middleware in ASP.NET Core?

common middleware in ASP.NET Core:

Understanding the ASP.NET Core Request Pipeline

ClientAuthenticationLoggingRoutingControllerResponseLoggingClient

How Middleware Works Internally

1. RequestDelegate

2. HttpContext

3. The next() Delegate

public class CustomMiddleware
{
    private readonly RequestDelegate _next;

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

    public async Task InvokeAsync(HttpContext context)
    {
        // You can add custom logic here before passing to next middleware
        Console.WriteLine("Request incoming: " + context.Request.Path);

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

        // You can also add logic after the next middleware has run
        Console.WriteLine("Response outgoing: " + context.Response.StatusCode);
    }
}

How to Create Custom Middleware in ASP.NET Core 8 (Step-by-Step)

Step 1: Create a Middleware Class

RequestLoggingMiddleware.cs
using System.Diagnostics;

public class RequestLoggingMiddleware
{
    private readonly RequestDelegate _next;

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

    public async Task InvokeAsync(HttpContext context)
    {
        var stopwatch = Stopwatch.StartNew();

        Console.WriteLine($"Incoming Request: {context.Request.Method} {context.Request.Path}");

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

        stopwatch.Stop();

        Console.WriteLine($"Response Status Code: {context.Response.StatusCode}");
        Console.WriteLine($"Request completed in {stopwatch.ElapsedMilliseconds} ms");

        // Add custom header
        context.Response.Headers.Add("X-Custom-Header", "MiddlewareDemo");
    }
}

Step 2: (Optional but Recommended) Create an Extension Method

RequestLoggingMiddlewareExtensions.cs
public static class RequestLoggingMiddlewareExtensions
{
    public static IApplicationBuilder UseRequestLogging(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<RequestLoggingMiddleware>();
    }
}

Step 3: Register Middleware in Program.cs

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

// Register custom middleware
app.UseRequestLogging();

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

app.Run();

Step 4: Run and Test the Application

dotnet run
https://localhost:5001/
Hello World!
Incoming Request: GET /
Response Status Code: 200
Request completed in 15 ms

How It Fits in the Request Pipeline

RequestCustom MiddlewareNext MiddlewareEndpoint
ResponseCustom MiddlewareNext MiddlewareEndpoint

Real-World Use Cases for Custom Middleware

Built-In Middleware in ASP.NET Core 8

app.UseRequestLogging();

1. Authentication Middleware

builder.Services.AddAuthentication("Bearer")
    .AddJwtBearer("Bearer", options =>
    {
        options.Authority = "https://your-auth-server";
        options.Audience = "your-api";
    });

var app = builder.Build();

app.UseAuthentication();
RequestAuthenticationNext Middleware
HttpContext.User
HttpContext.User

2. Authorization Middleware

builder.Services.AddAuthorization();

var app = builder.Build();

app.UseAuthorization();
app.MapGet("/secure", () => "Secure Data")
   .RequireAuthorization();
RequestAuthenticationAuthorizationEndpoint

3. Routing Middleware

var app = builder.Build();

app.UseRouting();

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

4. Exception Handling Middleware

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/error");
}
app.UseDeveloperExceptionPage();
RequestException HandlingRest of Pipeline

5. Static Files Middleware

app.UseStaticFiles();
wwwroot/index.html
https://localhost:5001/index.html
RequestStatic Files → (if file existsreturn file)
                         → (if notnext middleware)

How Built-In Middleware Fits Together

app.UseExceptionHandler("/error");

app.UseStaticFiles();

app.UseRouting();

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

app.MapControllers();

app.Run();
Middleware in ASP.NET Core 8

Middleware Order Matters

app.UseRouting();

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

app.MapControllers();
Request

Routing

Authentication (Who are you?)

Authorization (Are you allowed?)

Endpoint

Response
app.UseRouting();

app.UseAuthorization();   // ❌ Wrong position
app.UseAuthentication();  // ❌ Comes too late

app.MapControllers();
Request

Routing

Authorization (User not authenticated yet!)

Authentication

Endpoint
403 Forbidden
app.UseAuthorization();
app.UseAuthentication();
app.UseAuthentication();
app.UseAuthorization();

Use vs Run vs Map in Middleware

1. app.Use() → Continues the Pipeline

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

    await next();  // Pass control to next middleware

    Console.WriteLine("After next middleware");
});

2. app.Run() → Terminates the Pipeline

app.Run(async context =>
{
    await context.Response.WriteAsync("Pipeline Ended Here");
});

3. app.Map() → Conditional Branching

app.Map("/admin", adminApp =>
{
    adminApp.Run(async context =>
    {
        await context.Response.WriteAsync("Welcome Admin");
    });
});

app.Run(async context =>
{
    await context.Response.WriteAsync("Public Page");
});
Request

Is path "/admin"?
   ├── YesAdmin BranchResponse
   └── NoContinue Main Pipeline

Conclusion

Once you understand that flow, everything else becomes easier:

Recommended Next Reads

🚀 Subscribe for Tech Updates

📧

👤

We respect your privacy. Unsubscribe anytime.