[ASP.NET Core] 使用 MemoryCache 為專案加上記憶體快取

平時都只會用 ConcurrentDictionary 自己刻 In-MemoryCache,玩了一下  MemoryCache 發現挺有趣的,筆記一下幾種做法

MemoryCache 在 ASP.NET Core是支援DI的,在 Startup 加上後就可以從建構式注入使用

public void ConfigureServices(IServiceCollection services)
{
    services.AddMemoryCache();
    
    services.AddControllers();
}

Get

  1. 直接取得 object
var val = (string)_cache.Get(key);
  1. 取得後轉為指定型別
var val = _cache.Get<string>(key);
  1. 嘗試取得
bool tryGetValue = _cache.TryGetValue(key, out var val);
  1. 取得並轉為指定型別,如果沒有就會用第二個參數的方法產生 value
var val = _cache.GetOrCreate<string>(key, entry => "new Value");

var val = await _cache.GetOrCreateAsync<string>(key, entry => "new Value");

Remove

就是刪除

_cache.Remove(key);

Set

  1. Add 並設定到期時間(Time、TimeSpan、IChangeToken)
_cache.Set(key, val);

_cache.Set(key, val, TimeSpan.FromSeconds(5));

_cache.Set(key, val, DateTimeOffset.Now);

_cache.Set(key, val, new CancellationChangeToken(new CancellationTokenSource(TimeSpan.FromSeconds(5)).Token));

  1. 指定優先度(在記憶體不足時,會依照優先度設定自動刪除資料)
_cache.Set(key, val, new MemoryCacheEntryOptions()
{
    Priority = CacheItemPriority.NeverRemove,
});
  1. 透過兩種方式限制 MemoryCache 的資料上限
  • Startup
services.AddMemoryCache(options => options.SizeLimit = 1000);
  • new MemoryCache()
var cache = new MemoryCache(new MemoryCacheOptions() { SizeLimit = 1000 });
  • Startup上設定的是Singleton的instance,在設定大小時要注意下,全專案使用的都是同一份實體

  • 接著再使用時,都必須設定這筆筆資料的size,否則會在 Set 時發生exception

_cache.Set(key, val, new MemoryCacheEntryOptions()
{
    Size = 1
});
  1. 在指定的時間後自動刪除資料(不是立即、不是立即、不是立即,很重要所以說三次)
_cache.Set(key, val, new MemoryCacheEntryOptions()
{
    AbsoluteExpiration = DateTimeOffset.UtcNow.AddSeconds(5),
});

_cache.Set(key, val, new MemoryCacheEntryOptions()
{
    AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(5)
});

  • 檢查過期資料的刪除時間點會在執行 Set、Get、Remove時觸發,而每兩次的檢查是有時間間隔的,可以從 MemoryCacheOptions 裡面的參數 ExpirationScanFrequency 設定間隔時間
// new
var memoryCache = new MemoryCache(new MemoryCacheOptions()
{
    ExpirationScanFrequency = TimeSpan.FromMinutes(1),
});

// startup
services.AddMemoryCache(options =>
{
    options.ExpirationScanFrequency = TimeSpan.FromMinutes(1)
})

  1. 在指定的時間內沒有被訪問就會刪除,被訪問就重新計時
_cache.Set(key, val, new MemoryCacheEntryOptions()
{
    SlidingExpiration = TimeSpan.FromSeconds(5)
});

  1. 在資料刪除後,執行指定的方法
_cache.Set(key, value, new MemoryCacheEntryOptions()
{
    SlidingExpiration = TimeSpan.FromSeconds(5),
    PostEvictionCallbacks =
    {
        new PostEvictionCallbackRegistration()
        {
            EvictionCallback = (key, o, reason, state) =>
            {
                Console.WriteLine(key + "remove");
            }
        }
    }
});
  1. 上述的所有過期方式都會在檢查程序執行時刪除資料,若需要過期即時刪除,可改用 IChangeToken 實現,過期時就會立即刪除資料並執行callback的方法
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
_cache.Set(key, value, new MemoryCacheEntryOptions()
{
    ExpirationTokens = { new CancellationChangeToken(cts.Token) },
    PostEvictionCallbacks =
    {
        new PostEvictionCallbackRegistration()
        {
            EvictionCallback = (key, o, reason, state) => Console.WriteLine(key + " remove")
        }
    }
});

Microsoft Docs ASP.NET Core 中的記憶體快取