⚙️ Your Custom Middleware Never Actually Runs for Static File Requests
A custom middleware is registered to log, authenticate, or modify every request – but requests for static files (images, CSS, JS) sail through completely untouched, because `UseStaticFiles()` short-circuits the pipeline and returns the file directly the moment it finds a match, without ever calling `next()` to continue on to whatever middleware comes after it.
🔎 The Problem
var app = builder.Build();
app.UseStaticFiles(); // <- handles /images/logo.png and returns immediately
app.Use(async (context, next) =>
{
Console.WriteLine($"Request: {context.Request.Path}");
await next();
});
app.MapControllers();
// Requests for actual files under wwwroot (e.g. /images/logo.png) never
// reach the logging middleware below UseStaticFiles - because
// UseStaticFiles ends the pipeline right there once it finds a matching
// file, it never calls next().
✅ Fix: Order Middleware by What Actually Needs to See Every Request
- Move any middleware that must run for EVERY request – logging, authentication checks, custom headers – to BEFORE `UseStaticFiles()` in the pipeline, so it executes regardless of whether the request ends up being served as a static file.
- If the goal is specifically to apply logic only to non-static requests (e.g., API routes), the current order is actually correct – the fix here is about matching pipeline order to actual intent, not always moving things earlier.
⚠️ The General Rule for ASP.NET Core Middleware Order
- Middleware order is not just a style choice – it directly determines which requests each piece of the pipeline ever sees, since any middleware can choose to short-circuit and never call `next()`. Reading the pipeline top-to-bottom as “what runs before what, and what might stop early” is the only reliable way to reason about it.
- `UseStaticFiles`, `UseRouting`, `UseAuthentication`, `UseAuthorization`, and `UseEndpoints`/`MapControllers` all have well-documented required relative ordering for exactly this reason – moving one without understanding why it was placed there is a common source of these silent gaps.
Middleware order isn’t a suggestion – it’s the actual list of who gets asked, and anything placed after a shortcut simply never gets a turn.
