Database queries, external API calls, and expensive computations can quickly become performance bottlenecks as application traffic grows. Even well-optimized SQL queries introduce latency when executed repeatedly for the same data.
Redis is a high-performance, in-memory data store commonly used as a distributed cache. When integrated with ASP.NET Core, Redis can significantly reduce response times, lower database load, and improve application scalability. However, caching the wrong data—or using an inappropriate caching strategy—can create stale data, unnecessary complexity, and difficult-to-debug consistency issues.
Rather than caching everything, this article explains practical Redis caching strategies, when to use them, and how to implement them effectively in ASP.NET Core.
Note: Caching improves performance only when cache hits significantly outnumber cache misses. Always measure cache effectiveness using metrics such as hit ratio and latency.
Why Use Redis Caching?
Every request that reaches the database consumes CPU, memory, network bandwidth, and I/O resources.
Caching frequently accessed data reduces repeated database queries and improves response times.
Typical benefits include:
Faster API responses
Reduced database load
Lower infrastructure costs
Improved scalability
Better user experience
Reduced latency for frequently accessed data
Not every piece of data should be cached. Frequently changing data may benefit more from direct database access.
What Should Be Cached?
Redis works best for data that is frequently read but changes infrequently.
Common candidates include:
Product catalogs
User profiles
Application configuration
Country and currency lists
Dashboard summaries
Frequently accessed reports
API responses
Session data
Avoid caching highly volatile or sensitive information unless there is a clear business requirement.
Caching Architecture
flowchart LR
A[Client]
B[ASP.NET Core API]
C{Cache Hit?}
D[(Redis)]
E[(SQL Server)]
A --> B
B --> C
C -->|Yes| D
C -->|No| E
E --> D
D --> B
B --> A
When cached data exists, Redis responds immediately. Otherwise, the application retrieves the data from the database, stores it in Redis, and returns the response.
Installing Redis
Install the Redis caching package.
dotnet add package Microsoft.Extensions.Caching.StackExchangeRedis
This package integrates Redis with the ASP.NET Core dependency injection system.
Configuring Redis
Register Redis during application startup.
builder.Services.AddStackExchangeRedisCache(options =>
{
options.Configuration =
"localhost:6379";
options.InstanceName = "MyApp:";
});
In production, replace the local connection string with your managed Redis endpoint.
Reading from the Cache
Inject IDistributedCache into your service.
public class ProductService
{
private readonly IDistributedCache _cache;
public ProductService(
IDistributedCache cache)
{
_cache = cache;
}
}
IDistributedCache provides a consistent API regardless of the underlying cache provider.
Cache-Aside Pattern
The Cache-Aside pattern is the most common Redis strategy.
var cacheKey = $"product:{id}";
var cached =
await _cache.GetStringAsync(cacheKey);
if (cached != null)
{
return JsonSerializer.Deserialize<Product>(cached);
}
var product =
await repository.GetByIdAsync(id);
await _cache.SetStringAsync(
cacheKey,
JsonSerializer.Serialize(product),
new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow =
TimeSpan.FromMinutes(10)
});
return product;
The application first checks Redis. If the data isn't found, it retrieves it from the database and stores it in the cache for future requests.
Setting Expiration Policies
Expiration prevents stale data from remaining in the cache indefinitely.
var options =
new DistributedCacheEntryOptions
{
SlidingExpiration =
TimeSpan.FromMinutes(15),
AbsoluteExpirationRelativeToNow =
TimeSpan.FromHours(1)
};
Combining sliding and absolute expiration provides a balance between freshness and performance.
Cache Invalidation
Whenever cached data changes, invalidate the associated cache entry.
await repository.UpdateAsync(product);
await _cache.RemoveAsync(
$"product:{product.Id}");
Failing to invalidate outdated entries is one of the most common causes of stale data.
Choosing an Expiration Strategy
Different data requires different expiration periods.
| Data Type | Suggested Expiration |
|---|---|
| Product Catalog | 30–60 minutes |
| User Profile | 10–30 minutes |
| Dashboard Data | 5–15 minutes |
| Configuration | Several hours |
| Reference Data | 24 hours or longer |
Join the conversation! Your thoughts help the community grow.