Skip to content

Aspnet Middleware

DodaTech 4 min read

title: ASP.NET Core Middleware — Complete Guide to Request Pipeline description: 'Learn ASP.NET Core middleware: pipeline architecture, built-in middleware, custom middleware, ordering, short-circuiting, and branching the pipeline with Map/Use/When.' date: 2026-06-28 lastmod: 2026-06-28 weight: 19 tags: [backend, aspnet]


ASP.NET Core middleware components form a pipeline that processes HTTP requests and responses, with each component choosing whether to pass to the next or short-circuit.

## What You'll Learn

By the end of this tutorial, you'll understand the request pipeline, use built-in middleware, create custom middleware, control pipeline ordering, short-circuit requests, and branch pipelines.

## Real-World Use

A request flows through: ExceptionHandler -> HttpsRedirection -> StaticFiles -> Routing -> Authentication -> Authorization -> Endpoint Middleware. Each piece handles one concern.

## Middleware Learning Path

```mermaid
flowchart LR
  A[Routing] --> B[Middleware]
  B --> C[DI]
  C --> D[Config]
  D --> E[EF Core]
  B --> F{You Are Here}
  style F fill:#f90,color:#fff

Built-in Middleware

var app = builder.Build();
// Order matters! Each middleware wraps the next.
if (app.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();  // 1. Error handling (outermost)
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}
app.UseHttpsRedirection();           // 2. Redirect HTTP to HTTPS
app.UseStaticFiles();                 // 3. Serve static files
app.UseRouting();                     // 4. Route matching
app.UseCors();                        // 5. Cross-origin
app.UseAuthentication();              // 6. Auth
app.UseAuthorization();              // 7. Authorization
app.MapControllers();                 // 8. Endpoint execution (innermost)

Custom Middleware

// Class-based middleware
public class RequestLoggingMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger _logger;
    public RequestLoggingMiddleware(RequestDelegate next, ILogger<RequestLoggingMiddleware> logger)
    {
        _next = next;
        _logger = logger;
    }
    public async Task InvokeAsync(HttpContext context)
    {
        var start = DateTime.UtcNow;
        _logger.LogInformation("Request: {Method} {Path}", 
            context.Request.Method, context.Request.Path);
        await _next(context);  // Call next middleware
        var elapsed = (DateTime.UtcNow - start).TotalMilliseconds;
        _logger.LogInformation("Response: {StatusCode} ({Elapsed}ms)", 
            context.Response.StatusCode, elapsed);
    }
}
// Extension method for cleaner registration
public static class MiddlewareExtensions
{
    public static IApplicationBuilder UseRequestLogging(this IApplicationBuilder app)
        => app.UseMiddleware<RequestLoggingMiddleware>();
}
// Register in Program.cs
app.UseRequestLogging();

Middleware Branching

// Map: branch based on path prefix
app.Map("/api", apiApp =>
{
    apiApp.UseAuthentication();
    apiApp.UseAuthorization();
    apiApp.Run(async context =>
    {
        await context.Response.WriteAsync("API endpoint");
    });
});

// MapWhen: branch based on condition
app.MapWhen(ctx => ctx.Request.Query.ContainsKey("admin"), adminBranch =>
{
    adminBranch.Use(async (context, next) =>
    {
        context.Response.Headers.Append("X-Admin-Mode", "true");
        await next();
    });
});

// Use: inline middleware
app.Use(async (context, next) =>
{
    context.Items["RequestStartTime"] = DateTime.UtcNow;
    await next();
});

Short-Circuiting

// Run: terminal middleware (never calls next)
app.Run(async context =>
{
    await context.Response.WriteAsync("Short-circuited!");
});

// Conditional short-circuit
app.Use(async (context, next) =>
{
    if (context.Request.Headers["X-Api-Key"] != "secret")
    {
        context.Response.StatusCode = 401;
        return;  // Don't call next
    }
    await next();
});

Common Mistakes

1. Wrong Middleware Order

Authentication before CORS blocks CORS preflight requests. StaticFiles before Routing serves files without route processing.

2. Not Calling await next()

Middleware that doesn't call await next() terminates the pipeline. Only do this intentionally (e.g., authentication failure).

3. Modifying Response After Sending

Once response headers are sent (first write), you can't modify status code or headers.

4. Heavy Operations in Middleware

Middleware runs on every request. Keep it lightweight. Put heavy operations (DB calls) in endpoint handlers.

5. Not Handling Exceptions

Without exception handling middleware, unhandled exceptions return 500 with no details.

Practice Questions

1. What is the middleware pipeline?

A series of components that process HTTP requests in order. Each component can process, pass, or short-circuit.

2. How do you create custom middleware?

Create a class with a RequestDelegate constructor parameter and an InvokeAsync(HttpContext) method.

3. What is the difference between Use, Map, and Run?

Use chains middleware. Map branches the pipeline by path prefix. Run is terminal middleware (ends the pipeline).

4. Why does middleware order matter?

Each middleware wraps the next. Exception handler must be outermost to catch exceptions from inner middleware.

5. Challenge: Create middleware that blocks requests from specific IP addresses.

public class IpBlockingMiddleware
{
    private readonly RequestDelegate _next;
    private readonly HashSet<string> _blockedIps;
    public IpBlockingMiddleware(RequestDelegate next, IConfiguration config)
    {
        _next = next;
        _blockedIps = config.GetSection("BlockedIPs").Get<HashSet<string>>() ?? new();
    }
    public async Task InvokeAsync(HttpContext context)
    {
        var ip = context.Connection.RemoteIpAddress?.ToString();
        if (ip != null && _blockedIps.Contains(ip))
        {
            context.Response.StatusCode = 403;
            return;
        }
        await _next(context);
    }
}

FAQ

What is the most important middleware?

Exception handling middleware should be first. Without it, unhandled exceptions crash the app or leak stack traces.

Can middleware access the DI container?

Yes. Inject services in the constructor (singleton) or in InvokeAsync (scoped).

How fast is middleware overhead?

Minimal. Well-written middleware adds microseconds. Built-in middleware is highly optimized.

What is the difference between middleware and filters?

Middleware runs on every request (pipeline level). Filters run on specific controllers/actions.

How do I write response in middleware?

Use context.Response.WriteAsync(). Write headers first, then body. Status code must be set before writing.

Mini Project: Request Timing Middleware

Create middleware that measures and logs request duration.

public class TimingMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger _logger;
    public TimingMiddleware(RequestDelegate next, ILogger<TimingMiddleware> logger)
    {
        _next = next;
        _logger = logger;
    }
    public async Task InvokeAsync(HttpContext context)
    {
        var stopwatch = System.Diagnostics.Stopwatch.StartNew();
        await _next(context);
        stopwatch.Stop();
        if (stopwatch.ElapsedMilliseconds > 1000)
            _logger.LogWarning("Slow request: {Path} took {Time}ms",
                context.Request.Path, stopwatch.ElapsedMilliseconds);
    }
}

What's Next

ASP.NET Core Dependency Injection ASP.NET Core Configuration

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro