Redis  

Implementing Distributed Caching with Redis in ASP.NET Core for Scalable Applications

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));
  • Absolute Expiration: Cache expires after a fixed duration.

  • Sliding Expiration: Resets expiration time when accessed.

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

IssueCauseSolution
Cache not updatingData stale in cacheUse versioning or invalidate on update
Memory overflowLarge dataset or no expirationUse expiration policies
Connection errorsRedis server unavailableCheck network/firewall, use retry logic
Serialization errorsInvalid JSON formatUse 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.