.Net Core 3.0:如何实现IMemoryCache按请求重置重建?
解决每个请求重置IMemoryCache的问题
兄弟,你这是踩了个很容易忽略的坑——默认的IMemoryCache是单例注册的!哪怕你的OrganizationRepository是Transient(每次请求都会新建实例),但它注入的始终是同一个全局缓存实例,所以上一次请求的缓存数据自然会保留下来。下面给你两种靠谱的解决方案:
方案1:给缓存键添加请求唯一前缀(最简单)
这个方案不需要改动缓存的注册逻辑,只需要在操作缓存时给键加上当前请求的唯一标识,确保不同请求的缓存数据互不干扰:
首先,给你的Repository注入IHttpContextAccessor来获取请求上下文:
public class OrganizationRepository : IOrganizationRepository { private readonly IMemoryCache _cache; private readonly string _requestUniquePrefix; public OrganizationRepository(IMemoryCache cache, IHttpContextAccessor httpContextAccessor) { _cache = cache; // 用请求的TraceIdentifier作为唯一前缀,确保每个请求的缓存键唯一 _requestUniquePrefix = httpContextAccessor.HttpContext.TraceIdentifier + "_"; } // 示例:添加缓存的方法 public void AddCacheItem(string key, object value) { var scopedKey = _requestUniquePrefix + key; _cache.Set(scopedKey, value); } // 示例:获取缓存的方法 public T GetCacheItem<T>(string key) { var scopedKey = _requestUniquePrefix + key; _cache.TryGetValue(scopedKey, out T result); return result; } }
别忘了在Program/Startup里注册IHttpContextAccessor:
services.AddHttpContextAccessor();
这种方案的好处是对现有代码改动极小,而且请求结束后,这些带前缀的缓存条目可以通过缓存过期策略自动清理,你也可以写个中间件在请求结束时手动移除。
方案2:注册请求级别的(Scoped)缓存实例(完全独立)
如果你真的想要每个请求都拥有完全独立的缓存实例,那可以自己封装一个Scoped的缓存实现:
先创建一个请求级别的缓存包装类,实现IMemoryCache接口:
public class RequestScopedCache : IMemoryCache, IDisposable { private readonly MemoryCache _internalCache; public RequestScopedCache() { _internalCache = new MemoryCache(new MemoryCacheOptions()); } // 实现IMemoryCache的所有接口方法,直接委托给内部的MemoryCache public bool TryGetValue(object key, out object value) { return _internalCache.TryGetValue(key, out value); } public ICacheEntry CreateEntry(object key) { return _internalCache.CreateEntry(key); } public void Remove(object key) { _internalCache.Remove(key); } public void Dispose() { _internalCache.Dispose(); } }
然后在服务注册时,把默认的单例IMemoryCache替换为Scoped的自定义实现:
// 替换默认的Singleton IMemoryCache为请求级别的实现 services.AddScoped<IMemoryCache, RequestScopedCache>(); // 你的Repository注册保持不变 services.AddTransient<IOrganizationRepository, OrganizationRepository>();
这样每个请求都会创建一个全新的RequestScopedCache实例,请求结束后会被自动释放,缓存数据也就跟着清空了。不过这个方案需要你实现IMemoryCache的所有接口,稍微繁琐一点,但能完全满足你“每个请求重建缓存”的需求。
小提醒:方案2的
MemoryCache实例创建开销极低,完全不用担心性能问题。
内容的提问来源于stack exchange,提问作者ShaneKm
相关产品推荐
相关产品推荐

