0Pricing
C# Academy · Lesson

Middleware & Filters in Minimal APIs

Add authentication, authorization, exception handling, and endpoint filters to Minimal API pipelines.

Middleware & Filters in Minimal APIs is a free C# Academy lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the C# Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Middleware vs Endpoint Filters

ASP.NET Core has two extensibility layers: middleware (wraps the entire pipeline, runs for every request) and endpoint filters (run only for specific endpoints). Both work in Minimal APIs.

Adding Middleware to Minimal APIs

Standard ASP.NET Core middleware is added with app.Use* methods. The order matters — middleware runs in the order it is registered.

var app = builder.Build();

app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.UseRateLimiter();

app.MapGet("/secure", () => "Protected endpoint")
   .RequireAuthorization();

app.Run();

Inline Endpoint Filters

Endpoint filters are like middleware scoped to a single endpoint. Use AddEndpointFilter to add a filter inline. Filters can short-circuit by returning a result without calling next.

app.MapGet("/guarded", () => "Secret data")
   .AddEndpointFilter(async (ctx, next) =>
   {
       var header = ctx.HttpContext.Request.Headers["X-Api-Key"];
       if (header != "my-secret-key")
           return Results.Unauthorized();

       return await next(ctx); // proceed to handler
   });

Class-Based Endpoint Filters

Implement IEndpointFilter to create reusable filters. They can be applied to individual endpoints or entire route groups.

public class LoggingFilter : IEndpointFilter
{
    private readonly ILogger<LoggingFilter> _logger;
    public LoggingFilter(ILogger<LoggingFilter> logger) => _logger = logger;

    public async ValueTask<object?> InvokeAsync(
        EndpointFilterInvocationContext ctx,
        EndpointFilterDelegate next)
    {
        _logger.LogInformation("Before: {Path}", ctx.HttpContext.Request.Path);
        var result = await next(ctx);
        _logger.LogInformation("After: {Path}",  ctx.HttpContext.Request.Path);
        return result;
    }
}

// Apply to a group
app.MapGroup("/api").AddEndpointFilter<LoggingFilter>();

Exception Handling Middleware

Use app.UseExceptionHandler or the built-in ProblemDetails middleware to catch unhandled exceptions and return RFC 7807 problem responses.

builder.Services.AddProblemDetails();

var app = builder.Build();

app.UseExceptionHandler();
// OR for custom logic:
app.UseExceptionHandler(errApp =>
    errApp.Run(async ctx =>
    {
        var ex = ctx.Features.Get<IExceptionHandlerFeature>()?.Error;
        ctx.Response.StatusCode = 500;
        await ctx.Response.WriteAsJsonAsync(new { error = ex?.Message });
    }));

Short-Circuit Middleware

Use app.MapShortCircuit() (.NET 8+) or Results.StatusCode() in a filter to immediately return a response without running the full pipeline.

// Block known bad bots at the edge
app.MapGet("/robots.txt", () => "User-agent: *\nDisallow: /")
   .ShortCircuit(); // .NET 8: returns response immediately

// Or in a filter:
app.MapGet("/maintenance", () => "OK")
   .AddEndpointFilter((ctx, next) =>
       ValueTask.FromResult<object?>(Results.StatusCode(503)));

Rate Limiting in .NET 7+

The built-in rate limiter middleware protects endpoints from abuse. Apply policies globally or per endpoint with RequireRateLimiting().

using System.Threading.RateLimiting;

builder.Services.AddRateLimiter(opt =>
{
    opt.AddFixedWindowLimiter("fixed", o =>
    {
        o.PermitLimit     = 10;
        o.Window          = TimeSpan.FromSeconds(10);
        o.QueueLimit      = 0;
        o.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
    });
    opt.RejectionStatusCode = StatusCodes.Status429TooManyRequests;
});

app.UseRateLimiter();
app.MapGet("/search", Search).RequireRateLimiting("fixed");

CORS Configuration

Configure CORS policies in services and apply them globally or per endpoint to control which origins can access your API.

builder.Services.AddCors(opt =>
    opt.AddPolicy("AllowFrontend", policy =>
        policy.WithOrigins("https://myapp.com")
              .AllowAnyHeader()
              .AllowAnyMethod()));

app.UseCors("AllowFrontend");

// Or per endpoint:
app.MapGet("/public-data", () => "data")
   .RequireCors("AllowFrontend");

Output Caching Middleware

AddOutputCache caches responses server-side. Apply it to specific endpoints to serve cached responses without hitting the database on every request.

builder.Services.AddOutputCache();

app.UseOutputCache();

app.MapGet("/products", async (AppDbContext db) =>
    Results.Ok(await db.Products.AsNoTracking().ToListAsync()))
   .CacheOutput(p => p.Expire(TimeSpan.FromMinutes(5)));

Filter Order and Chaining

Filters execute in the order they are added (outermost first, innermost last — like middleware). You can chain multiple filters on the same endpoint or group.

app.MapPost("/orders", CreateOrder)
   .AddEndpointFilter<LoggingFilter>()      // runs first
   .AddEndpointFilter<ValidationFilter>()   // runs second
   .AddEndpointFilter<AuthFilter>()         // runs third
   .RequireAuthorization();                 // JWT checked by middleware

Real-World: API Key Middleware

A reusable API key middleware that reads the key from a header and short-circuits with 401 if invalid.

public class ApiKeyMiddleware
{
    private readonly RequestDelegate _next;
    private readonly string _expectedKey;

    public ApiKeyMiddleware(RequestDelegate next, IConfiguration cfg)
    {
        _next = next;
        _expectedKey = cfg["ApiKey"] ?? throw new Exception("ApiKey not configured");
    }

    public async Task InvokeAsync(HttpContext ctx)
    {
        if (!ctx.Request.Headers.TryGetValue("X-Api-Key", out var key)
            || key != _expectedKey)
        {
            ctx.Response.StatusCode = 401;
            await ctx.Response.WriteAsync("Invalid API key");
            return;
        }
        await _next(ctx);
    }
}

app.UseMiddleware<ApiKeyMiddleware>();

Quick Check

What is the key difference between middleware and endpoint filters in Minimal APIs?

Recap: Middleware & Filters

Key takeaways:

  • Middleware (UseX) runs globally in pipeline order for every request
  • Endpoint filters (AddEndpointFilter) are scoped to specific endpoints or groups
  • Implement IEndpointFilter for reusable, DI-friendly filter classes
  • Built-in middleware: rate limiting, CORS, output caching, exception handling
  • Filter order matters — they nest like middleware (first added = outermost)

Frequently asked questions

Is the “Middleware & Filters in Minimal APIs” lesson free?

Yes — the full text of “Middleware & Filters in Minimal APIs” is free to read here on the web, and the C# Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the C# Academy course, upgrade to CoddyKit PRO.

What will I learn in “Middleware & Filters in Minimal APIs”?

Add authentication, authorization, exception handling, and endpoint filters to Minimal API pipelines. You practise C# Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start C# Academy?

No prior experience is required. C# Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Middleware & Filters in Minimal APIs” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this C# Academy lesson?

Yes. Every C# Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Creating Your First Minimal API
  2. Route Groups, Parameters & Validation
  3. Middleware & Filters in Minimal APIs
  4. OpenAPI, Versioning & Deployment
← Back to C# Academy