I "added caching" to a read-heavy endpoint, deployed it, and watched the database graph stay exactly where it was. The response had a nice Cache-Control: public, max-age=60 header on it. The browser was happy. The database was still answering every single call, because the thing I'd added only ever talked to the browser.
That's the trap I want to show here, with a counter instead of a hand-wave. I built two endpoints that do the same "expensive" work, one guarded by a cache header and one by ASP.NET Core's output caching, and I incremented a number inside each handler. The number only moves when the handler actually runs. So if caching is doing anything at all, the number stops climbing. Everything below is from running it on .NET 10, Release build, in a small Linux container. Not a benchmark lab — I just want to see which handler runs and how often.
Two endpoints that look identical
Here's the whole setup.…