Middleware — The Request Pipeline
Before a ReadingRoom endpoint sees a request, it has already been redirected to HTTPS, had its login token checked, and been timed. Each of those jobs is a middleware: a small piece of code in a chain. Get the chain's order wrong and security checks quietly stop working.
The rule
Registered order is running order: in on the way down, out on the way back.
Every app.Use... call in Program.cs adds one link to the pipeline. A request walks down the chain, reaches an endpoint, and the response walks back up through the same links in reverse.
var app = builder.Build();
app.UseExceptionHandler("/error"); // 1. catches anything thrown below it
app.Use(async (context, next) => // 2. custom: time every request
{
var started = Stopwatch.GetTimestamp();
await next(context); // everything below runs here
var ms = Stopwatch.GetElapsedTime(started).TotalMilliseconds;
context.RequestServices.GetRequiredService<ILogger<Program>>()
.LogInformation("{Path} took {Ms} ms", context.Request.Path, ms);
});
app.UseHttpsRedirection(); // 3. send http:// visitors to https://
app.UseAuthentication(); // 4. who is this?
app.UseAuthorization(); // 5. may they do this?
app.MapControllers(); // 6. the endpoints
app.Run();Code before await next(context) runs on the way in; code after it runs on the way out. A middleware that does not call next short-circuits: it writes the response itself and nothing further down runs. That is how UseHttpsRedirection answers with a redirect, or how UseStaticFiles serves a file without touching your endpoints.
Endpoints themselves (MapControllers, MapGet) always run at the bottom of the chain, after every Use... call. Built-in middleware covers most needs: exception handling, HTTPS redirection, static files, routing, CORS, authentication, authorization, rate limiting and response compression.
The shortcut
Read Program.cs top to bottom and ask of each line: what must already be true when this runs? Authorization needs a known user, so authentication comes first. The exception handler must wrap everything, so it comes first of all.
Exception handler
Nothing to do yet; it waits to catch errors from below.
The trap: UseAuthorization() above UseAuthentication(). It compiles and starts, but authorization then checks a user nobody has identified yet, so every caller looks anonymous.
Drills
Answer fast — trust the rule.
In what order do middleware components run for an incoming request?
A middleware writes a 403 response and never calls next. What happens to later middleware?
Where should app.UseExceptionHandler() go?
In a custom middleware, when does code after await next(context) run?
Remember
- Registered order is running order: in on the way down, out on the way back.
- Ask "what must already be true?" — authentication before authorization, exception handler first.
- Not calling
nextshort-circuits the rest of the pipeline.
