Skip to content

Middleware Pattern

Cross-cutting concerns handled through ASP.NET Core middleware.

Overview

flowchart TB
    subgraph Pipeline["Request Pipeline"]
        direction TB
        A[Request] --> B[CorrelationId]
        B --> C[SecurityHeaders]
        C --> D[RateLimiting]
        D --> E[Authentication]
        E --> F[PermsVersion]
        F --> G[GlobalExceptionHandler]
        G --> H[Controller/MediatR]
        H --> I[Response]
    end

Correlation ID

Tracks requests across services for debugging and logging.

public class CorrelationIdMiddleware(RequestDelegate next)
{
    public async Task InvokeAsync(HttpContext context)
    {
        var correlationId = context.Request.Headers["X-Correlation-Id"].FirstOrDefault()
            ?? Guid.NewGuid().ToString();

        context.Items["CorrelationId"] = correlationId;
        context.Response.Headers["X-Correlation-Id"] = correlationId;

        using (logger.BeginScope(new { CorrelationId = correlationId }))
        {
            await next(context);
        }
    }
}

Security Headers

See Security Headers for the full list.

Permission Version

Validates JWT permission version against current user state.

flowchart TB
    A[Request with JWT] --> B{Has PermsVersion claim?}
    B -->|No| C[Continue]
    B -->|Yes| D{Matches DB version?}
    D -->|Yes| C
    D -->|No| E[401 Unauthorized]
    E --> F[Client refreshes token]

Used when:

  • User role changes
  • Group membership changes
  • Module access changes

Global Exception Handler

Maps exceptions to structured error responses (see Error Handling for the full mapping table). Responses use RFC 7807 Problem Details format.

Rate Limiting

Per-endpoint rate limiting via [RateLimit] attribute:

[RateLimit(requests: 30, seconds: 60)]
public async Task<IActionResult> GetMarkers()

[RateLimit(5, 60, isGlobal: true)]
public async Task<IActionResult> Login()
  • requests — Max requests allowed in window
  • seconds — Time window duration
  • isGlobal — When false (default), limits per user/IP; when true, shared across all users

Registration Order

Middleware order matters - registered in Program.cs:

app.UseCorrelationId();
app.UseSecurityHeaders();
app.UseRateLimiter();
app.UseAuthentication();
app.UseAuthorization();
app.UsePermsVersion();
app.UseGlobalExceptionHandler();