Introduction
In high-traffic applications, database calls can quickly become a performance bottleneck. To improve speed and scalability, caching is one of the most effective optimization strategies.
While in-memory caching works for single-server applications, it fails in distributed or cloud environments where multiple instances of the same application are deployed. That’s where Redis, a high-performance in-memory data store, comes in — offering distributed caching that works across all instances of your application.
In this article, we’ll go step-by-step through implementing distributed caching with Redis in ASP.NET Core, including setup, configuration, and real-world use cases.
1. Understanding Distributed Caching
A distributed cache is a shared cache accessible by multiple application servers. Unlike in-memory caching, which is local to one instance, distributed caching ensures consistent data availability across the entire infrastructure.
Benefits of Distributed Caching
Scalability: Works seamlessly across multiple servers.
Performance: Reduces database round trips.
Fault Tolerance: Redis supports persistence and replication.
Centralized Cache Management: Easy invalidation and monitoring.
When to Use Distributed Caching
Multi-instance deployments (Azure App Service, AWS ECS, Kubernetes, etc.)
API-heavy applications requiring high read performance.
Microservices architectures sharing common data.
2. What is Redis?
Redis (Remote Dictionary Server) is an open-source, in-memory data structure store that can be used as:
Cache
Message broker
Real-time data store
It stores data as key-value pairs, making it extremely fast. Redis supports data persistence, replication, and clustering — ideal for enterprise-grade distributed caching.
3. Setting up Redis
You can set up Redis in multiple ways:
Option 1: Using Docker
docker run -d --name redis -p 6379:6379 redis
Option 2: Using Azure Redis Cache
If deploying in the cloud, create a Redis instance via the Azure Portal and note the hostname and access key.
4. Installing Redis in ASP.NET Core
Add the following NuGet package to your project:
dotnet add package Microsoft.Extensions.Caching.StackExchangeRedis
This package integrates ASP.NET Core’s caching abstraction with StackExchange.Redis, the most popular Redis client.
5. Configuring Redis in Program.cs
var builder = WebApplication.CreateBuilder(args);
// Configure Redis Distributed Cache
builder.Services.AddStackExchangeRedisCache(options =>
{
options.Configuration = "localhost:6379"; // Replace with Azure Redis endpoint if hosted
options.InstanceName = "MyApp_"; // Prefix for cache keys
});
builder.Services.AddControllers();
var app = builder.Build();
app.MapControllers();
app.Run();
This sets up Redis as the distributed cache provider for your ASP.NET Core application.
6. Using Redis Cache in a Controller
Example: Caching Product Data
Let’s say you want to cache product details fetched from the database.
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Distributed;
using System.Text.Json;
[ApiController]
[Route("api/[controller]")]
public class ProductController : ControllerBase
{
private readonly IDistributedCache _cache;
private readonly ILogger<ProductController> _logger;
public ProductController(IDistributedCache cache, ILogger<ProductController> logger)
{
_cache = cache;
_logger = logger;
}
[HttpGet("{id}")]
public async Task<IActionResult> GetProduct(int id)
{
string cacheKey = $"product_{id}";
string? cachedData = await _cache.GetStringAsync(cacheKey);
if (cachedData != null)
{
_logger.LogInformation("Cache hit for product {Id}", id);
return Ok(JsonSerializer.Deserialize<Product>(cachedData));
}
// Simulate DB fetch
var product = new Product { Id = id, Name = "Laptop", Price = 999.99M };
_logger.LogInformation("Cache miss for product {Id}. Storing in cache...", id);
var serialized = JsonSerializer.Serialize(product);
var cacheOptions = new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(10),
SlidingExpiration = TimeSpan.FromMinutes(5)
};
await _cache.SetStringAsync(cacheKey, serialized, cacheOptions);
return Ok(product);
}
}
public record Product
{
public int Id { get; init; }
public string Name { get; init; }
public decimal Price { get; init; }
}
Explanation
Cache Miss: When data is not found in Redis, fetch from DB and store it.
Cache Hit: If found, serve data directly from Redis, reducing DB load.
Expiration: Data automatically expires after the defined time.
7. Managing Cache Expiration and Invalidation
You can configure cache lifetime using DistributedCacheEntryOptions:
var options = new DistributedCacheEntryOptions()
.SetAbsoluteExpiration(TimeSpan.FromMinutes(30))
.SetSlidingExpiration(TimeSpan.FromMinutes(10));
To manually clear cache
await _cache.RemoveAsync("product_101");
8. Handling Complex Objects
Redis stores strings, but you can easily serialize/deserialize JSON objects as shown above. For more complex caching (like lists or hash sets), you can use the StackExchange.Redis client directly.
using StackExchange.Redis;
var redis = ConnectionMultiplexer.Connect("localhost:6379");
var db = redis.GetDatabase();
await db.HashSetAsync("user:1", new HashEntry[] {
new HashEntry("name", "Rajesh"),
new HashEntry("role", "Admin")
});
9. Real-World Use Cases
a. Session Storage
Redis is ideal for storing user sessions in distributed web apps:
builder.Services.AddDistributedRedisCache(...);
builder.Services.AddSession();
app.UseSession();
b. API Response Caching
Cache frequently accessed GET API responses for better performance.
c. Rate Limiting
Redis can track API usage counts per user or IP to implement rate limiting.
10. Common Issues and Solutions
| Issue | Cause | Solution |
|---|
| Cache not updating | Data stale in cache | Use versioning or invalidate on update |
| Memory overflow | Large dataset or no expiration | Use expiration policies |
| Connection errors | Redis server unavailable | Check network/firewall, use retry logic |
| Serialization errors | Invalid JSON format | Use consistent serialization strategy |
11. Monitoring Redis Performance
Use tools like
RedisInsight – GUI for real-time monitoring
Azure Redis Metrics – Built-in monitoring dashboard
StackExchange.Redis Profiling – View slow commands
Example for Azure Redis CLI
INFO stats
12. Best Practices
Use consistent cache keys (e.g., entity_type_id).
Always define cache expiration to prevent stale data.
Store small objects — don’t cache huge data sets.
Implement cache invalidation strategy after updates.
Use connection pooling with StackExchange.Redis.
Conclusion
Redis-based distributed caching is a cornerstone for scalable, high-performance ASP.NET Core applications. It allows your app to handle massive traffic with minimal latency while keeping the database workload under control.
By following the approach outlined in this guide — setting up Redis, configuring caching policies, and using it for real-world scenarios like API responses or sessions — you can create resilient, performant applications ready for production and cloud environments.