Hello! Welcome back to our journey on optimizing Azure applications.
In the previous lesson, you successfully provisioned and configured your first Azure Cache for Redis instance. You now have a running cache in the cloud and its connection string at the ready. This is the infrastructure foundation we need.
Today, we move from infrastructure to application code. This lesson directly addresses the learning outcome: Connect to Azure Cache for Redis from a .NET application using the StackExchange.Redis library. You will leverage your strong C# and .NET background to write the code that brings your cache to life, enabling you to set, retrieve, and manage cached data. This is a critical hands-on step that paves the way for implementing advanced caching patterns.
1. The Core Component: StackExchange.Redis
To interact with Redis from a .NET application, we use a client library. The industry standard and most recommended library is StackExchange.Redis, developed and used by the team at Stack Overflow.
The central object in this library is the ConnectionMultiplexer. It is a powerful and highly optimized component that manages the network connections to your Redis server. Here are the two most important things to know about it:
- Thread-Safe: It is designed to be safely used by multiple threads concurrently.
- Singleton Pattern: It is intended to be created once at application startup and reused throughout the application's lifetime. Creating a new
ConnectionMultiplexerfor each operation is an anti-pattern that leads to poor performance and connection issues.
Therefore, we will register it as a singleton instance in our application's dependency injection container.

2. Setting Up the Connection
Let's begin by seeing how to add the library to a project and configure the ConnectionMultiplexer. Your experience with dependency injection in .NET Core will make this process very familiar.
The following video provides an excellent demonstration of this initial setup.
How to effectively use Redis Cache in .NET Core (Framework, Standard)
Watch this clip from the video 'How to effectively use Redis Cache in .NET Core' by Nick Chapsas. It clearly demonstrates installing the correct NuGet package and registering the IConnectionMultiplexer as a singleton in Program.cs.
Please watch from 02:28 to 04:29. Focus on these key steps: Installing the StackExchange.Redis NuGet package. Registering IConnectionMultiplexer as a singleton service. Using ConnectionMultiplexer.Connect() with a connection string retrieved from configuration.
As you saw in the video, the setup involves two main parts:
- Adding the
StackExchange.RedisNuGet package to your project. - In
Program.cs, adding the service registration:builder.Services.AddSingleton<IConnectionMultiplexer>(sp => { var configuration = sp.GetRequiredService<IConfiguration>(); var connectionString = configuration.GetConnectionString("Redis"); // Or another config key return ConnectionMultiplexer.Connect(connectionString); });
This ensures a single, shared instance of the ConnectionMultiplexer is available throughout your application.
3. Building a Reusable Cache Service
While you could use the IConnectionMultiplexer directly in your controllers, it's a best practice to create an abstraction. We'll build a dedicated cache service to encapsulate the logic for getting, setting, and removing data. This aligns with the Single Responsibility Principle and makes your code cleaner, more maintainable, and easier to test.
Our service will handle a crucial detail: serialization. Redis stores data as strings (or raw bytes). To store complex .NET objects (like a WeatherForecast object), you must first serialize them into a format like JSON. When you retrieve the data, you must then deserialize it back into a .NET object.
The following video provides a comprehensive, step-by-step walkthrough of building such a service.
How Azure Redis Cache can make your .NET 7 API Super Fast!
This video, 'How Azure Redis Cache can make your .NET 7 API Super Fast!' by Israel Quiroz, provides a complete implementation of a generic cache service. It's an excellent, practical guide.
Please watch the segment from 02:57 to 08:29. Follow along as the presenter builds the caching layer. Pay close attention to: NuGet Package (02:57 - 03:16): Confirms the installation of StackExchange.Redis. Interface and Class (03:16 - 04:44): The creation of IRedisCache and RedisCache to define a contract for caching operations. Method Implementation (04:44 - 07:23): The detailed implementation of GetCacheData, SetCacheData, and RemoveData. Note how System.Text.Json (or Newtonsoft.Json) is used for serialization and deserialization, and how IDatabase is obtained from the ConnectionMultiplexer. DI Registration (07:23 - 08:29): Registering both the ConnectionMultiplexer singleton and the scoped IRedisCache service in Program.cs.
4. Implementing the Cache Service in Your Project
Let's consolidate the concepts from the videos into a concrete implementation. You will now apply this to a .NET Web API project.
Step 1: Project and Configuration
-
Create a new ASP.NET Core Web API project in Visual Studio.
-
Install the
StackExchange.Redispackage via the NuGet Package Manager. -
In your
appsettings.jsonfile, add the primary connection string you saved from the previous lesson.{ "ConnectionStrings": { "Redis": "your-cache-name.redis.cache.windows.net:6380,password=YOUR_ACCESS_KEY,ssl=True,abortConnect=False" }, // ... other settings }
Step 2: The Interface and Service Class
Create a new folder named Services. Inside it, create the interface and the class for your cache service.
ICacheService.cs
public interface ICacheService
{
Task<T> GetData<T>(string key);
Task<bool> SetData<T>(string key, T value, DateTimeOffset expirationTime);
Task<bool> RemoveData(string key);
}
CacheService.cs
This implementation uses System.Text.Json for serialization.
using StackExchange.Redis;
using System.Text.Json;
public class CacheService : ICacheService
{
private readonly IDatabase _db;
public CacheService(IConnectionMultiplexer multiplexer)
{
_db = multiplexer.GetDatabase();
}
public async Task<T> GetData<T>(string key)
{
var value = await _db.StringGetAsync(key);
if (!string.IsNullOrEmpty(value))
{
return JsonSerializer.Deserialize<T>(value);
}
return default;
}
public async Task<bool> SetData<T>(string key, T value, DateTimeOffset expirationTime)
{
TimeSpan expiryTime = expirationTime.DateTime.Subtract(DateTime.Now);
var isSet = await _db.StringSetAsync(key, JsonSerializer.Serialize(value), expiryTime);
return isSet;
}
public async Task<bool> RemoveData(string key)
{
bool _isKeyExist = await _db.KeyExistsAsync(key);
if (_isKeyExist)
{
return await _db.KeyDeleteAsync(key);
}
return false;
}
}
Step 3: Dependency Injection in Program.cs
Register your services.
using StackExchange.Redis;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
// Register Redis ConnectionMultiplexer as a Singleton
builder.Services.AddSingleton<IConnectionMultiplexer>(sp =>
ConnectionMultiplexer.Connect(builder.Configuration.GetConnectionString("Redis"))
);
// Register the custom Cache Service
builder.Services.AddScoped<ICacheService, CacheService>();
var app = builder.Build();
// ... rest of Program.cs
Step 4: Using the Service in a Controller
Finally, inject ICacheService into a controller and use it. This example demonstrates a basic check-and-set logic.
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private readonly ICacheService _cacheService;
private static readonly string[] Summaries = new[] { "Freezing", "Bracing", "Chilly" };
public WeatherForecastController(ICacheService cacheService)
{
_cacheService = cacheService;
}
[HttpGet(Name = "GetWeatherForecast")]
public async Task<IEnumerable<WeatherForecast>> Get()
{
// Define a unique key for this data
var cacheKey = "weatherForecast";
// Try to get data from cache
var cachedData = await _cacheService.GetData<IEnumerable<WeatherForecast>>(cacheKey);
if (cachedData != null)
{
// Data found in cache, return it
return cachedData;
}
// Data not in cache, generate it
var forecast = Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
}).ToArray();
// Set the data in cache with an expiration time (e.g., 1 minute)
var expirationTime = DateTimeOffset.Now.AddMinutes(1);
await _cacheService.SetData(cacheKey, forecast, expirationTime);
// Return the newly generated data
return forecast;
}
}
When you run this code and call the endpoint, the first request will generate the data and store it in your Azure Cache for Redis. Subsequent requests within one minute will retrieve the data directly from the cache, which will be significantly faster.
Conclusion
Excellent work! You have successfully bridged the gap between your Azure infrastructure and your .NET application. You now have the practical skills to connect to a Redis cache, manage the connection efficiently, and perform core data operations.
Key Takeaways:
- The
StackExchange.Redislibrary is the standard for connecting .NET applications to Redis. - Its core
ConnectionMultiplexerobject should always be managed as a long-lived singleton. - Creating a separate service to abstract cache operations is a robust design pattern that improves code quality.
- Since Redis stores string data, complex .NET objects must be serialized (e.g., to JSON) before being stored and deserialized upon retrieval.
Next Steps
The code you wrote today is a foundational implementation of a very common caching strategy. In our next lesson, we will formalize this strategy by studying the cache-aside pattern. We'll discuss how it helps reduce database load and improve response times, and we will refine our code to clearly separate data source logic from caching logic.