11. Hosting, WebApplication and Kestrel
Sections
Reading settings
Natural voice recorded for this course, the same in every browser.
No voice for this language in this browser.
More voices
Code and English terms
Off: the page’s voice reads everything, with no pause between two voices.
No voice for this language in this browser.
More voices
More voices: Microsoft Edge has natural online voices, and Windows (Settings › Time & language › Speech), macOS and Android install others.
WebApplication is the composition root for configuration, logging, dependency injection, middleware and endpoints. The generic host owns application lifetime; Kestrel owns the network transport.
What the builder actually assembles
Section titled “What the builder actually assembles”WebApplication.CreateBuilder loads configuration sources, registers logging and host services, then exposes Services and WebHost for explicit changes. Build freezes that service graph into an application. StartAsync starts hosted services and the server; StopAsync begins graceful shutdown.
The executable lesson binds Kestrel to an ephemeral loopback port, maps /health, makes a real HTTP request and records lifetime callbacks:
started callback observed: TrueGET /health: 200 {"status":"ready"}graceful stop callbacks observed: stopping=True, stopped=TrueThis proves the course composition, not production readiness. Production still needs declared request/body limits, timeouts, forwarded-header trust, TLS termination, readiness behavior and a shutdown budget longer than the longest accepted request.
Graceful does not mean infinite
Section titled “Graceful does not mean infinite”ApplicationStopping tells code to stop accepting or producing new work. In-flight work should observe cancellation and either finish inside the budget or leave durable recovery evidence. A BackgroundService that ignores cancellation can extend shutdown until the host timeout expires.
In containers, align the host shutdown timeout with the orchestrator termination grace period. If the outer deadline is shorter, the process is killed before .NET can complete its graceful path.
Run the proof
Section titled “Run the proof”dotnet run --project code/csharp-advanced/Advanced -c Release -- l11The checked transcript is expected/l11.txt.
Exercises
Section titled “Exercises”- Add a slow endpoint that observes
RequestAborted, begin shutdown, and record whether the request completes inside the host timeout. - Set a small Kestrel request-body limit and prove the status returned for a larger body.
- Put the app behind one proxy and test forwarded headers with one trusted proxy and one spoofed direct request.
Solutions
- Use a
TaskCompletionSourceto prove the request entered, callStopAsyncwith a bounded token, and make the endpoint log cancellation. The test passes only when the observed behavior matches the declared shutdown contract. - Configure the limit before
Build, send bodies just below and above it, and assert both the status and that the endpoint was not invoked for the rejected body. - Configure known proxies/networks explicitly. The direct request must not be able to choose its client identity through
X-Forwarded-For.