Data

Two-level caching in .NET with FusionCache and Redis

This guide shows how to combine FusionCache's in-process L1 memory with a shared Redis L2 layer in a product catalog API. The author keeps Clean Architecture boundaries intact and focuses on correct cache behavior rather than raw speed numbers. It is a practical starting point for developers who run several instances and need to plan freshness and invalidation.

Published
Reading time
40 min read
agent run #12
agent run #12
Go to original dev.to

Report this story

Is something wrong with the summary, or do you own this content? Your message comes straight to my inbox.

Type of message

Key points

  • FusionCache 2.9.0 layers an in-process L1 cache over a Redis L2 layer; the core package alone only gives you L1.
  • TTL controls freshness while eviction is a separate event driven by Redis memory limits such as maxmemory.
  • Reads follow cache aside: check L1, then L2, and only then run the factory query against the database.
  • The cache wraps the Application read interface as a decorator, so Domain and Application never reference FusionCache types.
  • The local demo uses redis:8.2-alpine with maxmemory 128mb and allkeys-lru; production needs private networking, ACLs and TLS.

This tutorial walks through combining FusionCache with Redis in a product catalog API built with Clean Architecture. The database stays the source of truth, while an in-process L1 cache and a shared Redis L2 layer speed up reads across several instances. The author puts correct behavior ahead of impressive benchmark numbers, stressing that TTL is a freshness policy, that memory eviction is a separate event, and that a database change does not refresh existing copies on its own.

The design splits the code into Domain, Application, Infrastructure and Api projects, so the Application layer never references FusionCache or Redis types. Caching wraps the product query reader as a decorator. The setup uses FusionCache 2.9.0 with its System.Text.Json serializer and Redis backplane, plus Microsoft's StackExchangeRedis provider at 10.0.9, targeting net10.0 with a redis:8.2-alpine container. The local Redis config caps memory at 128 MB with allkeys-lru and disables persistence.

Real-world use

  • A product catalog API running on several instances that serves frequently read product details without hitting the database each time.
  • An e-commerce backend that can tolerate briefly stale product data after price changes, as long as the freshness policy is explicit.
  • A Clean Architecture .NET service that needs to add caching around existing query readers without changing the domain or application code.

Why it matters

Wrapping the cache as a decorator and defining TTL, eviction and invalidation rules up front keeps both performance and freshness predictable across instances. As the article stresses, cache behavior is a design contract, so it matters more than any single benchmark number.

This summary was generated by the agent from the original post on DEV Community: #dotnet. The full text and all rights belong to its author and publisher. Go to original

Related stories

Feedback

Found a bug or have an idea? Your message lands straight in my inbox.

Type of message