.NET Framework 4.8分布式缓存实现及滑动缓存方案问询
.NET Framework 4.8 基于Redis实现滑动分布式缓存方案
原代码问题分析
- 错误将StackExchange.Redis的
IDatabase强制转换为ASP.NET Core专属的IDistributedCache,两者无继承关系,直接导致_distributedcache实例无效,触发空引用异常。 - 构造函数中重复赋值
_distributedcache,逻辑冗余且错误。
解决方案:基于StackExchange.Redis原生实现滑动缓存
无需依赖ASP.NET Core的IDistributedCache,直接基于你已验证可行的RedisCache类扩展滑动缓存逻辑。滑动缓存的核心是每次读取缓存时自动刷新键的过期时间,确保键在被访问时不会过期。
1. 扩展缓存接口(ICache)
添加滑动缓存的方法定义:
public interface ICache { Task<T> GetCache<T>(string key); Task<bool> SetCache<T>(string key, T value, int timeSpan); // 新增滑动缓存方法 Task<T> GetSlidingCache<T>(string key, TimeSpan slidingExpiration); Task<bool> SetSlidingCache<T>(string key, T value, TimeSpan slidingExpiration); }
2. 修改RedisCache类实现滑动逻辑
基于现有可运行的RedisCache,添加滑动缓存的实现:
public class RedisCache : ICache { private readonly IDatabase _cache; private readonly ConnectionMultiplexer _redisConnection; public RedisCache() { var redisConStr = ConfigurationManager.ConnectionStrings["Redis"].ConnectionString; _redisConnection = ConnectionMultiplexer.Connect(redisConStr); _cache = _redisConnection.GetDatabase(); } // 保留原有的GetCache和SetCache方法不变 public async Task<T> GetCache<T>(string key) { var redisObj = await _cache.StringGetAsync(key); if (!redisObj.HasValue) return default(T); return JsonConvert.DeserializeObject<T>(redisObj, new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Serialize, PreserveReferencesHandling = PreserveReferencesHandling.Objects }); } public async Task<bool> SetCache<T>(string key, T value, int timeSpan) { if (value == null) return true; var strVal = JsonConvert.SerializeObject(value, Formatting.Indented, new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Serialize, PreserveReferencesHandling = PreserveReferencesHandling.Objects }); var cacheTimeSpan = timeSpan > 0 ? TimeSpan.FromMinutes(timeSpan) : TimeSpan.FromMinutes(10); return await _cache.StringSetAsync(key, strVal, cacheTimeSpan); } // 实现滑动缓存获取方法:读取值后刷新过期时间 public async Task<T> GetSlidingCache<T>(string key, TimeSpan slidingExpiration) { var redisObj = await _cache.StringGetAsync(key); if (!redisObj.HasValue) return default(T); // 每次读取成功后,刷新键的过期时间(滑动核心逻辑) await _cache.KeyExpireAsync(key, slidingExpiration); return JsonConvert.DeserializeObject<T>(redisObj, new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Serialize, PreserveReferencesHandling = PreserveReferencesHandling.Objects }); } // 实现滑动缓存设置方法:初始设置过期时间 public async Task<bool> SetSlidingCache<T>(string key, T value, TimeSpan slidingExpiration) { if (value == null) return true; var strVal = JsonConvert.SerializeObject(value, Formatting.Indented, new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Serialize, PreserveReferencesHandling = PreserveReferencesHandling.Objects }); // 设置键值时指定初始滑动过期时间 return await _cache.StringSetAsync(key, strVal, slidingExpiration); } }
3. 调用示例
获取滑动缓存
var slidingExpiration = TimeSpan.FromMinutes(30); List<EmployeeRole> employeeRoles = _cache.GetSlidingCache<List<EmployeeRole>>(Constants.CACHE_CALENDARROLES, slidingExpiration).GetAwaiter().GetResult();
设置滑动缓存
var slidingExpiration = TimeSpan.FromMinutes(30); var employeeRoles = ReadEmployeeRoles(i_RoleId, i_VendorId); await CacheHelper.Cache.SetSlidingCache<List<ModelEmployeeRole>>(Constants.CACHE_EmployeeROLES, employeeRoles, slidingExpiration);
关键说明
- 滑动过期依赖
KeyExpireAsync方法,每次读取缓存成功后刷新键的过期时间,确保键在持续访问时不会过期。 - 若需要统一管理过期时间,可将滑动过期时长配置到
web.config中,避免硬编码。 - 避免在同步代码中直接使用
GetAwaiter().GetResult(),建议将调用方改为异步方法,防止死锁风险。
内容的提问来源于stack exchange,提问作者Susmitha
相关产品推荐
相关产品推荐

