Convex-addisalem.Shared.Caching
1.0.0
dotnet add package Convex-addisalem.Shared.Caching --version 1.0.0
NuGet\Install-Package Convex-addisalem.Shared.Caching -Version 1.0.0
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Convex-addisalem.Shared.Caching" Version="1.0.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Convex-addisalem.Shared.Caching" Version="1.0.0" />
<PackageReference Include="Convex-addisalem.Shared.Caching" />
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Convex-addisalem.Shared.Caching --version 1.0.0
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#r "nuget: Convex-addisalem.Shared.Caching, 1.0.0"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Convex-addisalem.Shared.Caching@1.0.0
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Convex-addisalem.Shared.Caching&version=1.0.0
#tool nuget:?package=Convex-addisalem.Shared.Caching&version=1.0.0
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
Convex.Shared.Caching
Caching utilities for Convex microservices.
Features
- Memory Caching: In-memory caching for fast access
- Redis Caching: Distributed caching with Redis
- JSON Serialization: Automatic JSON serialization/deserialization
- Expiration Support: Configurable cache expiration
- Bulk Operations: Get/set multiple items at once
- GetOrSet Pattern: Lazy loading with caching
- High Performance: Optimized for billion-record scenarios
- Thread Safety: Concurrent access with semaphore control
- Batch Processing: Parallel processing for bulk operations
- Exception Handling: Proper exception propagation
Installation
<PackageReference Include="Convex.Shared.Caching" Version="1.0.0" />
Quick Start
1. Register Services
// Memory caching
services.AddConvexMemoryCache();
// Redis caching
services.AddConvexRedisCache("localhost:6379");
2. Use in Your Service
public class UserService
{
private readonly IConvexCache _cache;
public UserService(IConvexCache cache)
{
_cache = cache;
}
public async Task<User?> GetUserAsync(int userId)
{
var cacheKey = $"user:{userId}";
return await _cache.GetOrSetAsync(cacheKey, async () =>
{
return await _userRepository.GetByIdAsync(userId);
}, TimeSpan.FromMinutes(15));
}
}
Memory Caching
Basic Setup
services.AddConvexMemoryCache();
Usage
// Set value
await _cache.SetAsync("key", "value", TimeSpan.FromMinutes(5));
// Get value
var value = await _cache.GetAsync<string>("key");
// Check if exists
var exists = await _cache.ExistsAsync("key");
// Remove value
await _cache.RemoveAsync("key");
Redis Caching
Basic Setup
services.AddConvexRedisCache("localhost:6379");
Advanced Configuration
services.AddConvexRedisCache(options =>
{
options.Configuration = "localhost:6379";
options.InstanceName = "Convex";
});
GetOrSet Pattern
Lazy Loading
public async Task<List<User>> GetUsersAsync()
{
return await _cache.GetOrSetAsync("users:all", async () =>
{
return await _userRepository.GetAllAsync();
}, TimeSpan.FromHours(1));
}
With Factory Function
public async Task<User> GetUserAsync(int userId)
{
var cacheKey = $"user:{userId}";
return await _cache.GetOrSetAsync(cacheKey, async () =>
{
var user = await _userRepository.GetByIdAsync(userId);
if (user == null)
throw new NotFoundException($"User {userId} not found");
return user;
}, TimeSpan.FromMinutes(30));
}
Bulk Operations
Get Multiple Items
var keys = new[] { "user:1", "user:2", "user:3" };
var users = await _cache.GetManyAsync<User>(keys);
Set Multiple Items
var users = new Dictionary<string, User>
{
["user:1"] = user1,
["user:2"] = user2,
["user:3"] = user3
};
await _cache.SetManyAsync(users, TimeSpan.FromMinutes(15));
Remove Multiple Items
var keys = new[] { "user:1", "user:2", "user:3" };
var removedCount = await _cache.RemoveManyAsync(keys);
Exception Handling
Input Validation
// ✅ Library validates inputs and throws specific exceptions
try
{
await _cache.GetAsync<User>(null); // Throws ArgumentException
}
catch (ArgumentException ex)
{
// Handle invalid input
Console.WriteLine($"Invalid input: {ex.Message}");
}
Cache Failures
// ✅ Let cache exceptions bubble up naturally
try
{
var user = await _cache.GetAsync<User>("user:123");
}
catch (RedisException ex)
{
// Handle Redis connection issues
_logger.LogError(ex, "Redis connection failed");
// Implement fallback logic
}
catch (JsonException ex)
{
// Handle serialization issues
_logger.LogError(ex, "Failed to deserialize cached data");
}
Best Practice: Application-Level Error Handling
public async Task<User?> GetUserWithFallbackAsync(int userId)
{
try
{
var cacheKey = $"user:{userId}";
return await _cache.GetOrSetAsync(cacheKey, async () =>
{
return await _userRepository.GetByIdAsync(userId);
}, TimeSpan.FromMinutes(15));
}
catch (Exception ex)
{
// Log the error and implement fallback
_logger.LogError(ex, "Cache operation failed for user {UserId}", userId);
// Fallback to database directly
return await _userRepository.GetByIdAsync(userId);
}
}
Cache Patterns
Cache-Aside Pattern
public async Task<User?> GetUserAsync(int userId)
{
var cacheKey = $"user:{userId}";
var user = await _cache.GetAsync<User>(cacheKey);
if (user == null)
{
user = await _userRepository.GetByIdAsync(userId);
if (user != null)
{
await _cache.SetAsync(cacheKey, user, TimeSpan.FromMinutes(30));
}
}
return user;
}
Write-Through Pattern
public async Task<User> CreateUserAsync(User user)
{
// Save to database
var createdUser = await _userRepository.CreateAsync(user);
// Update cache
var cacheKey = $"user:{createdUser.Id}";
await _cache.SetAsync(cacheKey, createdUser, TimeSpan.FromMinutes(30));
return createdUser;
}
Write-Behind Pattern
public async Task UpdateUserAsync(User user)
{
// Update cache immediately
var cacheKey = $"user:{user.Id}";
await _cache.SetAsync(cacheKey, user, TimeSpan.FromMinutes(30));
// Queue for database update
await _updateQueue.EnqueueAsync(user);
}
Configuration
appsettings.json
{
"ConnectionStrings": {
"Redis": "localhost:6379"
},
"Cache": {
"DefaultExpiration": "00:15:00",
"UserExpiration": "00:30:00",
"SessionExpiration": "01:00:00"
}
}
Environment Variables
export REDIS_CONNECTION_STRING="localhost:6379"
export CACHE_DEFAULT_EXPIRATION="00:15:00"
Performance Features
High-Performance Design
- Concurrency Control: SemaphoreSlim with configurable max concurrency (default: 1000)
- Batch Processing: 100-item batches for bulk operations
- Parallel Processing: Concurrent execution for bulk operations
- JSON Optimization: Performance-tuned serialization settings
- Thread Safety: Concurrent access control for high-scale scenarios
Advanced Concurrency
// Configure max concurrency for high-scale scenarios
services.AddSingleton<IConvexCache>(provider =>
{
var distributedCache = provider.GetRequiredService<IDistributedCache>();
return new ConvexCache(distributedCache, maxConcurrency: 2000); // Custom concurrency limit
});
Batch Processing Example
// Process thousands of items efficiently
var keys = Enumerable.Range(1, 10000).Select(i => $"user:{i}").ToArray();
var users = await _cache.GetManyAsync<User>(keys); // Automatically batched
// Set thousands of items efficiently
var userData = users.ToDictionary(u => $"user:{u.Id}", u => u);
await _cache.SetManyAsync(userData, TimeSpan.FromHours(1)); // Automatically batched
Exception Handling
- Input Validation: Comprehensive parameter validation with specific exceptions
- Exception Propagation: Let exceptions bubble up naturally
- No Exception Swallowing: Clear error information for debugging
- Resource Management: Proper cleanup with try-finally blocks
Best Practices
- Use Appropriate Expiration: Set reasonable expiration times
- Cache Keys: Use consistent, descriptive cache keys
- Error Handling: Handle cache failures gracefully
- Serialization: Ensure objects are serializable
- Memory Usage: Monitor memory usage for in-memory caching
- Exception Handling: Let exceptions bubble up to application layer
- Performance: Use bulk operations for multiple items
- Thread Safety: Library handles concurrency automatically
License
This project is licensed under the MIT License.
| 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. |
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
-
net9.0
- Microsoft.Extensions.Caching.Abstractions (>= 9.0.0)
- Microsoft.Extensions.Caching.Memory (>= 9.0.0)
- Microsoft.Extensions.Caching.StackExchangeRedis (>= 9.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 9.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 9.0.0)
- Microsoft.Extensions.Options (>= 9.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0 | 92 | 10/17/2025 |
Initial release of Convex.Shared.Caching