dotnet 核心中的内存缓存

Memory Cache in dotnet core

我正在尝试编写一个 class 来处理 .net 核心 class 库中的内存缓存。如果我不使用核心那么我可以写

using System.Runtime.Caching;
using System.Collections.Concurrent;

namespace n{
public class MyCache
{
        readonly MemoryCache _cache;
        readonly Func<CacheItemPolicy> _cachePolicy;
        static readonly ConcurrentDictionary<string, object> _theLock = new ConcurrentDictionary<string, object>();

        public MyCache(){
            _cache = MemoryCache.Default;
            _cachePolicy = () => new CacheItemPolicy
            {
                SlidingExpiration = TimeSpan.FromMinutes(15),
                RemovedCallback = x =>    
                {
                    object o;
                    _theLock.TryRemove(x.CacheItem.Key, out o);
                }
            };
        }
        public void Save(string idstring, object value){
                lock (_locks.GetOrAdd(idstring, _ => new object()))
                {
                        _cache.Add(idstring, value, _cachePolicy.Invoke());
                }
                ....
        }
}
}

在 .Net 核心中我找不到 System.Runtime.Cache。在阅读了 .net 核心 In Memory Cache 之后,我添加了参考 Microsoft.Extensions.Caching.Memory (1.1.0) 并尝试了

using System.Collections.Concurrent;
using Microsoft.Extensions.Caching.Memory;

namespace n
{
    public class MyCache
    {
            readonly MemoryCache _cache;
            readonly Func<CacheItemPolicy> _cachePolicy;
            static readonly ConcurrentDictionary<string, object> _theLock = new ConcurrentDictionary<string, object>();
            public MyCache(IMemoryCache memoryCache){
                   _cache = memoryCache;// ?? **MemoryCache**; 
            }

            public void Save(string idstring, object value){
                    lock (_locks.GetOrAdd(idstring, _ => new object()))
                    {
                            _cache.Set(idstring, value, 
                              new MemoryCacheEntryOptions()
                              .SetAbsoluteExpiration(TimeSpan.FromMinutes(15))
                              .RegisterPostEvictionCallback(
                                    (key, value, reason, substate) =>
                                    {
                                        object o;
                                        _locks.TryRemove(key.ToString(), out o);
                                    }
                                ));
                    }
                    ....
            }
    }
}

希望保存方法中的代码没问题,尽管目前我的大部分 mycache 测试都失败了。任何人都可以指出什么是错的吗? 主要问题是关于构造函数我应该怎么做才能设置缓存 MemoryCache.Default

_cache = memoryCache ?? MemoryCache.Default; 

构造函数是:

using Microsoft.Extensions.Caching.Memory;

。 . .

MemoryCache myCache = new MemoryCache(new MemoryCacheOptions());

我的回答集中在“在 .Net 核心中我找不到 System.Runtime.Cache”,因为我 运行 遇到了同样的问题。对于在特定 OP 场景中使用 IMemoryCache,接受的答案很好。


有两个完全不同缓存implementations/solutions:

1 - System.Runtime.Caching/MemoryCache
2 - Microsoft.Extensions.Caching.Memory/IMemoryCache


System.Runtime.Caching/MemoryCache:
这与过去 ASP.Net MVC 的 HttpRuntime.Cache 几乎相同。 您可以在 ASP.Net CORE 上使用它而无需任何依赖项注入。这是如何使用它:

// First install 'System.Runtime.Caching' (NuGet package)

// Add a using
using System.Runtime.Caching;

// To get a value
var myString = MemoryCache.Default["itemCacheKey"];

// To store a value
MemoryCache.Default["itemCacheKey"] = myString;

Microsoft.Extensions.Caching.Memory
这与依赖注入紧密结合。这是一种实现方式:

// In asp.net core's Startup add this:
public void ConfigureServices(IServiceCollection services)
{
    services.AddMemoryCache();
}

在控制器上使用它:

// Add a using
using Microsoft.Extensions.Caching.Memory;

// In your controller's constructor, you add the dependency on the 'IMemoryCache'
public class HomeController : Controller
{
    private IMemoryCache _cache;
    public HomeController(IMemoryCache memoryCache)
    {
        _cache = memoryCache;
    }

    public void Test()
    {
        // To get a value
        string myString = null;
        if (_cache.TryGetValue("itemCacheKey", out myString))
        { /*  key/value found  -  myString has the key cache's value*/  }


        // To store a value
        _cache.Set("itemCacheKey", myString);
    }
}

正如@WillC 所指出的,这个答案实际上是 Cache in-memory in ASP.NET Core 文档的摘要。您可以在那里找到扩展信息。

如果您使用 Asp.net 核心,则无需为缓存自定义 SingleTon,因为 Asp.net 核心支持缓存 class.

要使用IMemoryCache将数据设置到服务器的内存中,您可以按照以下步骤操作:

public void Add<T>(T o, string key)
{
    if (IsEnableCache)
    {
        T cacheEntry;

        // Look for cache key.
        if (!_cache.TryGetValue(key, out cacheEntry))
        {
            // Key not in cache, so get data.
            cacheEntry = o;

            // Set cache options.
            var cacheEntryOptions = new MemoryCacheEntryOptions()
                // Keep in cache for this time, reset time if accessed.
                .SetSlidingExpiration(TimeSpan.FromSeconds(7200));

            // Save data in cache.
            _cache.Set(key, cacheEntry, cacheEntryOptions);
        }
    }
}
  • 通过构造函数注入 MemoryCache(从 nugget 获取引用 Microsoft.Extensions.Caching.Memory)
 private readonly IMemoryCache memoryCache;
  • 代码实现
 private IList<Employee> GetListFromCache()
        {
            const string Key = "employee";
            IList<Employee> cacheValue = null;
            if (!this.memoryCache.TryGetValue(Key, out cacheValue))
            {
                //// Key not in cache, so get data.
                cacheValue = this.context.Employee.AsNoTracking().Include(x => 
                x.Id).ToList();
                       
                //// Set cache options.
                var cacheEntryOptions = new MemoryCacheEntryOptions()
                    //// Keep in cache for this time, reset time if accessed.
                    .SetSlidingExpiration(TimeSpan.FromDays(1));

                //// Save data in cache.
                this.memoryCache.Set(Key, cacheValue, cacheEntryOptions);
            }

            return cacheValue;
        }

在 Startup.cs

中的 ConfigureServices 下注册 AddMemoryCache
 services.AddMemoryCache();
  • 为单元测试模拟 IMemoryCache
     /// <summary>Gets the memory cache.</summary>
        /// <returns> Memory cache object.</returns>
        public IMemoryCache GetMemoryCache()
        {
            var services = new ServiceCollection();
            services.AddMemoryCache();
            var serviceProvider = services.BuildServiceProvider();

            return serviceProvider.GetService<IMemoryCache>();
        }

//Inject memory cache in constructor for unit test
  this.memoryCache = text.GetMemoryCache();