FusionCache integration for AspNetZero/ABP Framework with hybrid caching and advanced resiliency features
$ dotnet add package CommunityAbp.AspNetZero.FusionCacheThis package integrates FusionCache into ASP.NET Zero and ABP Framework applications, providing a drop-in replacement for the standard Redis cache with advanced resiliency features and hybrid caching capabilities.
Install the core package:
dotnet add package CommunityAbp.AspNetZero.FusionCache
For distributed caching with Redis, install the Redis package:
dotnet add package CommunityAbp.AspNetZero.FusionCache.Redis
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
// Add FusionCache with default options
services.AddAbpFusionCache(options =>
{
options.DefaultCacheDuration = TimeSpan.FromMinutes(30);
options.EnableFailSafe = true;
options.EnableCacheStampedeProtection = true;
});
}
}public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
// Add FusionCache
services.AddAbpFusionCache(options =>
{
options.EnableDistributedCache = true;
options.EnableBackplane = true;
});
// Add Redis integration
services.AddAbpFusionCacheRedis(Configuration, options =>
{
options.ConnectionString = "localhost:6379";
options.EnableBackplane = true;
options.InstanceName = "MyApp:";
});
}
}Configure FusionCache in your module's PreInitialize method:
[DependsOn(typeof(AbpKernelModule))]
public class MyApplicationModule : AbpModule
{
public override void PreInitialize()
{
// Enable FusionCache
Configuration.Caching.UseFusionCache(options =>
{
options.DefaultCacheDuration = TimeSpan.FromMinutes(30);
options.EnableFailSafe = true;
options.EnableMultiTenancy = true;
});
}
}| Property | Type | Default | Description |
|---|---|---|---|
DefaultCacheDuration | TimeSpan | 30 minutes | Default duration for cached items |
EnableMemoryCache | bool | true | Enable L1 in-memory caching |
EnableDistributedCache | bool | false | Enable L2 distributed caching |
EnableFailSafe | bool | true | Serve stale data when cache backend is unavailable |
EnableCacheStampedeProtection | bool | true | Prevent cache stampede scenarios |
EnableEagerRefresh | bool | false | Proactively refresh cache before expiration |
EagerRefreshThreshold | float | 0.9f | Threshold (0-1) for eager refresh trigger |
EnableMultiTenancy | bool | true | Enable tenant-aware caching |
KeyPrefix | string | "AbpCache" | Prefix for all cache keys |
EnableBackplane | bool | false | Enable distributed cache synchronization |
| Property | Type | Default | Description |
|---|---|---|---|
ConnectionString | string | null | Redis connection string |
Database | int | 0 | Redis database index |
EnableBackplane | bool | false | Enable Redis backplane for cache sync |
BackplaneChannelPrefix | string | "AbpFusionCache" | Prefix for backplane channels |
ConnectTimeout | TimeSpan | 5 seconds | Connection timeout |
SyncTimeout | TimeSpan | 5 seconds | Synchronous operation timeout |
InstanceName | string | "AbpFusionCache" | Cache instance name |
public class ProductService
{
private readonly ICacheManager _cacheManager;
public ProductService(ICacheManager cacheManager)
{
_cacheManager = cacheManager;
}
public async Task<Product> GetProductAsync(int productId)
{
var cache = _cacheManager.GetCache("ProductCache");
return await cache.GetAsync(
productId.ToString(),
async () => await LoadProductFromDatabase(productId)
);
}
private async Task<Product> LoadProductFromDatabase(int productId)
{
// Your data loading logic
}
}public async Task<Product> GetProductAsync(int productId)
{
var cache = _cacheManager.GetCache("ProductCache");
return await cache.GetAsync(
productId.ToString(),
async () => await LoadProductFromDatabase(productId),
slidingExpireTime: TimeSpan.FromMinutes(10)
);
}The cache automatically handles tenant isolation:
// Cache keys are automatically prefixed with tenant ID
var tenantProduct = await cache.GetAsync(
"product:123",
async () => await GetTenantProduct(123)
);
// Different tenants get different cache entries for the same keyThe Redis integration looks for connection strings in this order:
AbpFusionCacheRedisOptions.ConnectionStringConnectionStrings:Redis in appsettings.jsonRedis:Configuration in appsettings.json{
"ConnectionStrings": {
"Default": "Server=localhost;Database=MyApp;...",
"Redis": "localhost:6379,password=mypassword"
},
"Redis": {
"Configuration": "localhost:6379"
}
}Configuration.Caching.Configure("UserCache", cache =>
{
cache.DefaultSlidingExpireTime = TimeSpan.FromHours(1);
});
Configuration.Caching.Configure("ProductCache", cache =>
{
cache.DefaultSlidingExpireTime = TimeSpan.FromMinutes(15);
});services.AddAbpFusionCache(options =>
{
options.EnableFailSafe = true;
options.DefaultCacheDuration = TimeSpan.FromMinutes(30);
// Stale data will be served for up to 1 hour if backend is down
});services.AddAbpFusionCache(options =>
{
options.EnableDistributedCache = true;
options.EnableBackplane = true;
options.EnableFailSafe = true;
});
services.AddAbpFusionCacheRedis(Configuration, options =>
{
options.ConnectionString = "redis-cluster:6379,redis-cluster:6380";
options.EnableBackplane = true;
options.BackplaneChannelPrefix = "MyApp:Cache:";
});services.AddAbpFusionCache(options =>
{
options.EnableEagerRefresh = true;
options.EagerRefreshThreshold = 0.9f; // Refresh at 90% of lifetime
});When multi-tenancy is enabled, the cache automatically:
Single Instance (Development)
options.EnableMemoryCache = true;
options.EnableDistributedCache = false;Multi-Instance (Production)
options.EnableMemoryCache = true;
options.EnableDistributedCache = true;
options.EnableBackplane = true;AddAbpFusionCache() is calledDefaultCacheDuration to expire items soonerEnableMemoryCache if distributed cache is sufficientMemoryCacheOptionsContributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the MIT License - see the LICENSE file for details.
For issues, questions, or contributions, please visit: