R3Polska.Cache.Redis
1.1.0
dotnet add package R3Polska.Cache.Redis --version 1.1.0
NuGet\Install-Package R3Polska.Cache.Redis -Version 1.1.0
<PackageReference Include="R3Polska.Cache.Redis" Version="1.1.0" />
<PackageVersion Include="R3Polska.Cache.Redis" Version="1.1.0" />
<PackageReference Include="R3Polska.Cache.Redis" />
paket add R3Polska.Cache.Redis --version 1.1.0
#r "nuget: R3Polska.Cache.Redis, 1.1.0"
#:package R3Polska.Cache.Redis@1.1.0
#addin nuget:?package=R3Polska.Cache.Redis&version=1.1.0
#tool nuget:?package=R3Polska.Cache.Redis&version=1.1.0
RedisCache
A lightweight, type-safe Redis cache wrapper for .NET that simplifies object storage with automatic JSON serialization/deserialization, batch operations, and flexible expiration policies.
Features
- π Simple API - Clean, intuitive interface for cache operations
- π Automatic Serialization - Seamless JSON serialization/deserialization of complex objects
- π¦ Batch Operations - Execute multiple Redis operations atomically
- β° Flexible Expiration - Support for both absolute and sliding expiration
- π List Support - Manage Redis lists with ease
- π Type-Safe - Full generic support for compile-time type checking
- π§ͺ Well Tested - Comprehensive unit and BDD test coverage
Installation
dotnet add package R3Polska.Cache.Redis --version 1.0.0
Or add to your .csproj file:
<PackageReference Include="R3Polska.Cache.Redis" Version="1.0.0" />
Quick Start
Basic Setup
using R3Polska.Cache.Redis;
using R3Polska.Cache.Redis.Contract;
using StackExchange.Redis;
// Create Redis connection
var redis = ConnectionMultiplexer.Connect("localhost:6379");
ICache cache = new RedisCache(redis);
Simple Get/Set Operations
// Set a string value with expiration
await cache.SetAsync("user:name", "John Doe", TimeSpan.FromHours(1));
// Get a string value
var name = await cache.GetAsync<string>("user:name");
// Set a complex object
var user = new User
{
Id = 1,
Name = "John Doe",
Email = "john@example.com"
};
await cache.SetAsync("user:1", user, TimeSpan.FromMinutes(30));
// Get the object back
var cachedUser = await cache.GetAsync<User>("user:1");
TryGet Pattern
// Check if key exists and get value in one operation
var (found, value) = await cache.TryGetValueAsync<string>("user:name");
if (found)
{
Console.WriteLine($"Found: {value}");
}
else
{
Console.WriteLine("Key not found");
}
Advanced Expiration Options
// Absolute expiration - expires at a specific time
var options = new RedisCacheEntryOptions
{
AbsoluteExpiration = DateTimeOffset.UtcNow.AddHours(2)
};
await cache.SetAsync("session:token", token, options);
// Sliding expiration - resets on each access
var slidingOptions = new RedisCacheEntryOptions
{
SlidingExpiration = TimeSpan.FromMinutes(15)
};
await cache.SetAsync("active:session", sessionData, slidingOptions);
// Combined expiration
var combinedOptions = new RedisCacheEntryOptions
{
AbsoluteExpiration = DateTimeOffset.UtcNow.AddHours(24),
SlidingExpiration = TimeSpan.FromMinutes(30)
};
await cache.SetAsync("user:preferences", prefs, combinedOptions);
Batch Operations
Execute multiple operations atomically:
await cache.ExecuteBatchAsync(batch =>
{
batch.SetAsync("user:1:name", "Alice");
batch.SetAsync("user:2:name", "Bob");
batch.SetAsync("user:3:name", "Charlie");
});
// Batch operations with results
var tasks = new List<Task<string?>>();
await cache.ExecuteBatchAsync(batch =>
{
tasks.Add(batch.GetAsync<string>("user:1:name"));
tasks.Add(batch.GetAsync<string>("user:2:name"));
tasks.Add(batch.GetAsync<string>("user:3:name"));
});
var names = await Task.WhenAll(tasks);
Working with Lists
// Add items to a list (left push)
await cache.LeftPushAsync("notifications:user:1", notification1);
await cache.LeftPushAsync("notifications:user:1", notification2);
// Add items to the right
await cache.RightPushAsync("queue:tasks", task1);
// Get list range
var notifications = await cache.GetRangeAsync<Notification>(
"notifications:user:1",
start: 0,
stop: 9 // Get first 10 items
);
// Get specific list item
var firstNotification = await cache.GetListItemAsync<Notification>(
"notifications:user:1",
index: 0
);
// Get list length
var count = await cache.GetListLengthAsync("notifications:user:1");
Removing Keys
// Remove a single key
var removed = await cache.RemoveAsync("old:key");
// Check if key exists
var exists = await cache.KeyExistsAsync("user:1");
API Reference
ICache Interface
Core Operations
Task<T?> GetAsync<T>(string key)- Get value by keyTask<(bool Found, T? Value)> TryGetValueAsync<T>(string key)- Try get with existence checkTask SetAsync<T>(string key, T value, TimeSpan? expiration = null)- Set value with optional expirationTask SetAsync<T>(string key, T value, RedisCacheEntryOptions options)- Set value with advanced optionsTask<bool> RemoveAsync(string key)- Remove keyTask<bool> KeyExistsAsync(string key)- Check if key exists
List Operations
Task LeftPushAsync<T>(string key, T value)- Push to list startTask RightPushAsync<T>(string key, T value)- Push to list endTask<IEnumerable<T>> GetRangeAsync<T>(string key, long start = 0, long stop = -1)- Get list rangeTask<T?> GetListItemAsync<T>(string key, long index)- Get item at indexTask<long> GetListLengthAsync(string key)- Get list length
Batch Operations
Task ExecuteBatchAsync(Action<ICacheBatch> batchOperations)- Execute operations atomically
RedisCacheEntryOptions
Configure cache entry expiration:
public class RedisCacheEntryOptions
{
public DateTimeOffset? AbsoluteExpiration { get; set; }
public TimeSpan? SlidingExpiration { get; set; }
}
Examples
Caching API Responses
public async Task<WeatherForecast> GetWeatherAsync(string city)
{
var cacheKey = $"weather:{city}";
var (found, forecast) = await cache.TryGetValueAsync<WeatherForecast>(cacheKey);
if (found)
{
return forecast!;
}
// Fetch from API
var freshForecast = await weatherApi.GetForecastAsync(city);
// Cache for 1 hour
await cache.SetAsync(cacheKey, freshForecast, TimeSpan.FromHours(1));
return freshForecast;
}
Session Management
public async Task<Session?> GetSessionAsync(string sessionId)
{
var options = new RedisCacheEntryOptions
{
// Session expires after 8 hours
AbsoluteExpiration = DateTimeOffset.UtcNow.AddHours(8),
// Reset expiration on each access (15 min idle timeout)
SlidingExpiration = TimeSpan.FromMinutes(15)
};
var session = await cache.GetAsync<Session>($"session:{sessionId}");
if (session != null)
{
// Refresh sliding expiration
await cache.SetAsync($"session:{sessionId}", session, options);
}
return session;
}
Activity Feed with Lists
public async Task AddActivityAsync(string userId, Activity activity)
{
var key = $"feed:{userId}";
// Add new activity to the front
await cache.LeftPushAsync(key, activity);
// Keep only last 50 activities (would need custom Redis command)
// For simplicity, set expiration on the list
await cache.SetAsync(key, activity, TimeSpan.FromDays(7));
}
public async Task<IEnumerable<Activity>> GetRecentActivitiesAsync(
string userId,
int count = 20)
{
var key = $"feed:{userId}";
return await cache.GetRangeAsync<Activity>(key, 0, count - 1);
}
Requirements
- .NET 9.0 or later
- Redis server (or Valkey compatible)
- StackExchange.Redis 2.10.1+
Building from Source
# Clone the repository
git clone https://github.com/recomaty/redis-cache.git
cd redis-cache
# Build the project
dotnet build
# Run unit tests
dotnet test RedisCache.Tests/RedisCache.Tests.csproj
# Run BDD tests (requires Redis/Valkey)
dotnet test RedisCache.BddTests/RedisCache.BddTests.csproj
# Generate coverage report
make test-coverage
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
This project is licensed under the BSD 3-Clause License - see the LICENSE file for details.
Authors
- IDCT Bartosz PachoΕek
- R3 Polska Sp. z o.o.
Acknowledgments
Built on top of the excellent StackExchange.Redis library.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net9.0
- StackExchange.Redis (>= 2.10.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.