You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 19:27:57