All Types of Caching in .NET: When to Use Each (Deep Dive, Part 2)
The second part of this caching deep dive compares FusionCache and Output Cache and closes with a decision guide for picking a layer. FusionCache adds a Redis backplane, fail-safe and factory timeouts on top of the HybridCache shape, while Output Cache middleware stores whole HTTP responses and evicts them by tag.
Key points
- FusionCache's Redis backplane publishes key removals over pub/sub so every instance invalidates its in-memory L1, the gap HybridCache leaves open.
- Default entry options cover `Duration`, `IsFailSafeEnabled`, `FailSafeMaxDuration` and `FactorySoftTimeout`; per-call overrides are limited when used as HybridCache.
- `AsHybridCache()` registers FusionCache as the HybridCache implementation, so existing handlers need no rewrite.
- Output Cache policies combine `Expire`, `SetVaryByRouteValue`/`SetVaryByQuery` and `Tag`; endpoints opt in with `CacheOutput("policy")`.
- `AddStackExchangeRedisOutputCache` replaces the per-process store so tag evictions reach all instances.
- Eviction belongs in one place, such as a domain event handler, not repeated in every write handler.
Part two of this caching series looks at the two options outside the built-in toolbox. FusionCache is a third-party hybrid cache with an in-memory L1 and a Redis L2, and it adds what HybridCache leaves out: a Redis pub/sub backplane that makes every instance drop its local copy on a write, plus fail-safe, factory soft timeouts and eager refresh. Existing handlers can keep injecting HybridCache through the `AsHybridCache()` adapter.
Output Cache is middleware that stores whole HTTP responses, so a hit skips the handler and the database. Policies declare expiry, variation via `SetVaryByRouteValue` or `SetVaryByQuery`, and tags for `EvictByTagAsync`; the default store is per-process, while `AddStackExchangeRedisOutputCache` shares it. It handles only GET and HEAD 200 responses and skips authenticated requests by default. The author picks HybridCache L1-only for simple apps, FusionCache when instances must agree immediately.
Real-world use
- A shipment tracking API running on several instances where a status update must not be served stale from another instance's memory.
- A public catalog endpoint whose JSON is identical for every visitor, cached as a full response and evicted by tag when prices change.
- A read-heavy service that has to keep answering while the database is slow, returning the last known value through FusionCache fail-safe.
- A rarely changing lookup table read thousands of times per request inside a single instance, kept in IMemoryCache because it should never be serialized.
Why it matters
Picking the wrong layer costs either correctness, with stale per-instance memory after a write, or latency, with a Redis round trip for data that could stay local; the decision path makes that trade-off explicit before it shows up in production.