How to Use Redis Caching With ASP.NET Core and .NET 8

Published

- 5 min read

How to Use Redis Caching With ASP.NET Core and .NET 8

img of How to Use Redis Caching With ASP.NET Core and .NET 8

How to Use Redis Caching With ASP.NET Core and .NET 8

Caching is a crucial aspect of web application development. It can help reduce the load on the database, speed up application performance, and improve scalability. Redis, an open-source, in-memory data structure store, is a popular choice for caching in ASP.NET Core applications. In this article, we will explore the steps involved in implementing Redis caching with ASP.NET Core and .NET 8.

Prerequisites

To follow along with this article, you should have the following:

  • .NET 8 SDK installed on your machine
  • Visual Studio 2022 (version 17.8 or later), Visual Studio Code, or JetBrains Rider
  • Redis server installed locally or access to a remote Redis server

Creating a New ASP.NET Core Application

Let’s start by creating a new ASP.NET Core application:

  1. Open your preferred IDE (Visual Studio, VS Code, or Rider).
  2. Create a new ASP.NET Core Web API project.
  3. Select ”.NET 8.0” as the target framework.
  4. Choose a project name and location, then create the project.

Adding Redis Cache

To use Redis caching in your ASP.NET Core application, you need to add the Redis cache provider to your project.

Add the Redis cache provider:

Run the following command in the terminal or Package Manager Console:

   dotnet add package Microsoft.Extensions.Caching.StackExchangeRedis

Configuring Redis Cache

Once you’ve added the Redis cache provider, configure it in the Program.cs file:

   using Microsoft.Extensions.Caching.StackExchangeRedis;

var builder = WebApplication.CreateBuilder(args);

// Add Redis cache
builder.Services.AddStackExchangeRedisCache(options =>
{
    options.Configuration = builder.Configuration.GetConnectionString("Redis");
    options.InstanceName = "SampleInstance";
});

// Other service registrations...

var app = builder.Build();

// Configure the HTTP request pipeline
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();

// Use Redis cache middleware
app.UseResponseCaching();

app.Run();

In this code, we’re adding the Redis cache provider to the IServiceCollection and configuring it with the Redis server address from the configuration. We’re also adding the Redis cache middleware to the application pipeline using the UseResponseCaching method.

Make sure to add the Redis connection string to your appsettings.json:

   {
  "ConnectionStrings": {
    "Redis": "localhost:6379"
  },
  // Other settings...
}

Using Redis Cache

Now that Redis cache is configured, you can use it in your application to cache data. You can do this by injecting the IDistributedCache interface into your controllers or services and using it to read from or write to the cache.

Example: Caching Product Data

Here’s an example of how to use Redis cache to cache a list of products:

   using System.Text.Json;
using Microsoft.Extensions.Caching.Distributed;

public class ProductService
{
    private readonly IDistributedCache _cache;
    private readonly ApplicationDbContext _dbContext;

    public ProductService(IDistributedCache cache, ApplicationDbContext dbContext)
    {
        _cache = cache;
        _dbContext = dbContext;
    }

    public async Task<List<Product>> GetProductsAsync()
    {
        var cacheKey = "ProductList";
        var cachedProducts = await _cache.GetStringAsync(cacheKey);

        if (cachedProducts != null)
        {
            return JsonSerializer.Deserialize<List<Product>>(cachedProducts);
        }

        var products = await _dbContext.Products.ToListAsync();
        var serializedProducts = JsonSerializer.Serialize(products);
        var cacheOptions = new DistributedCacheEntryOptions
        {
            AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30),
            SlidingExpiration = TimeSpan.FromMinutes(10)
        };

        await _cache.SetStringAsync(cacheKey, serializedProducts, cacheOptions);

        return products;
    }
}

In this code, we’re injecting IDistributedCache into our ProductService class and using it to cache a list of products. We’re using the SetStringAsync method to write the list of products to the cache and the GetStringAsync method to read the list of products from the cache.

Advanced Redis Caching Techniques

1. Cache Serialization

For better performance, consider using a more efficient serialization method like Protocol Buffers or MessagePack instead of JSON:

   using MessagePack;

// Serialization
var serializedProducts = MessagePackSerializer.Serialize(products);

// Deserialization
var deserializedProducts = MessagePackSerializer.Deserialize<List<Product>>(cachedData);

2. Distributed Locking

When multiple instances of your application are running, implement distributed locking to prevent race conditions:

   using StackExchange.Redis;

public async Task<List<Product>> GetProductsAsync()
{
    var cacheKey = "ProductList";
    var lockKey = `${cacheKey}_lock`;

    using (var redisLock = await _distributedLockFactory.CreateLockAsync(lockKey, TimeSpan.FromSeconds(10)))
    {
        if (await redisLock.AcquireAsync())
        {
            try
            {
                // Check cache and update if necessary
                // ...
            }
            finally
            {
                await redisLock.ReleaseAsync();
            }
        }
        else
        {
            // Wait and retry or handle unable to acquire lock
        }
    }
    
    // Return cached or fetched data
}

3. Cache Invalidation Strategies

Implement cache invalidation strategies to ensure data consistency:

  1. Time-based expiration: Already implemented in the example above.
  2. Event-based invalidation: Invalidate cache when data changes.
   public async Task UpdateProductAsync(Product product)
{
    await _dbContext.Products.UpdateAsync(product);
    await _dbContext.SaveChangesAsync();
    
    // Invalidate cache
    await _cache.RemoveAsync("ProductList");
}
  1. Version-based invalidation: Use a version number to track data changes.

Monitoring and Optimization

To ensure optimal performance of your Redis cache:

  1. Use Redis commands like INFO and MONITOR to track cache usage and performance.
  2. Implement logging and metrics collection in your application to monitor cache hit/miss rates.
  3. Consider using Redis Sentinel or Redis Cluster for high availability and scalability in production environments.

Conclusion

In this article, we’ve explored how to use Redis caching with ASP.NET Core and .NET 8. We’ve covered the basic setup, configuration, and usage of Redis cache, as well as some advanced techniques for optimizing your caching strategy. Redis caching can significantly improve the performance and scalability of your ASP.NET Core application by reducing database load and improving response times.

As you implement caching in your application, remember to carefully consider your caching strategy, including expiration policies, invalidation methods, and data consistency requirements. With proper implementation, Redis caching can be a powerful tool in your ASP.NET Core application’s performance optimization toolkit.

References