在ASP.NET Core应用中使用IMemoryCache缓存
Posted JimCarter
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在ASP.NET Core应用中使用IMemoryCache缓存相关的知识,希望对你有一定的参考价值。
文章目录
1. 简介
Caching通过减少生成内容所需的工作,显著提高应用的性能和可伸缩性。 Caching适用于不经常更改且生成成本高的数据。
ASP.NET Core支持多个不同的缓存。 最简单的缓存基于 IMemoryCache
。 IMemoryCache
属于内存缓存,存在于应用内部。如果使用内存缓存,后续请求需要都请求到这一个应用上,才能有效利用这个缓存,否则会有缓存一致性的问题。如果没办法保证这一点,则可以使用分布式缓存来解决。对于某些应用,分布式缓存可以支持比内存中缓存更高的横向扩展。使用分布式缓存可将缓存内存卸载到外部进程。
内存缓存可以存储任何对象,分布式缓存一般只能存储byte[]
。二者的储存方式一般都是键值对。
2. 内存缓存
2.1 使用 IMemoryCache
先介绍下过期时间:
- 绝对过期时间:假如设置为10s,则10s之后此缓存数据就会被清除。
- 滑动过期时间:假如设置为3s,如果3s之内有请求过来,则缓存失效日期为当前时间再加上3s。如果在有效时间内,没请求过来,则失效。
- 二者都进行设置:以最短的有效时间为主。假如绝对过期时间为10s,滑动过期时间为3s。如果3s没请求过来,则失效。如果每3s内就会有一个请求过来,则超过10s也会失效。
对于大多数应用IMemoryCache
默认已启用,可以直接使用(否则可以手动调用AddMemoryCache
)。
public class HomeController : Controller
private IMemoryCache _cache;
public HomeController(IMemoryCache memoryCache)
_cache = memoryCache;
2.2 获取缓存数据 GetOrCreate
、GetOrCreateAsync
和Get
DateTime cacheEntry;
string key="_blablabla";
//获取cache
if (!_cache.TryGetValue(key, out cacheEntry))
//没获取到,则分配一个值
cacheEntry = DateTime.Now;
//设置cache策略
var cacheEntryOptions = new MemoryCacheEntryOptions()
//设置3s的滑动过期时间(3s内如果有请求到,则自动再延长3s)
.SetSlidingExpiration(TimeSpan.FromSeconds(3));
//保存到cache
_cache.Set(key, cacheEntry, cacheEntryOptions);
//或者直接设置绝对过期时间
_cache.Set(key, cacheEntry, TimeSpan.FromDays(1));
获取时如果不存在则同时创建:
public async Task<IActionResult> CacheGetOrCreateAsynchronous()
var cacheEntry = await
_cache.GetOrCreateAsync(key, entry =>
entry.SlidingExpiration = TimeSpan.FromSeconds(3);
//也可以设置绝对过期时间(即使3s内一直有请求过来,超过10s也会过期。)
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(10);
return Task.FromResult(DateTime.Now);
);
return View("Cache", cacheEntry);
2.3 移除缓存
_cache.Remove(key)
2.4 缓存配置项 MemoryCacheEntryOptions
可以配置以下几个功能:
- 设置过期时间:这个前面已经讲过了
- 缓存优先级:共有四个优先级,低中高+永不移除(
CacheItemPriority.NeverRemove
)。当内存紧张上,系统会根据策略移除低中高优先级的缓存,不会移除NeverRemove优先级的缓存。 - 缓存回调:可通过
PostEvictionDelegate
设置一个回调,当缓存失效时,此回调会在另外一个线程上运行。
public IActionResult CreateCallbackEntry()
var cacheEntryOptions = new MemoryCacheEntryOptions()
//永不移除
.SetPriority(CacheItemPriority.NeverRemove)
//设置回调
.RegisterPostEvictionCallback(callback: EvictionCallback, state: this);
_cache.Set(_key, DateTime.Now, cacheEntryOptions);
return RedirectToAction("GetCallbackEntry");
private static void EvictionCallback(object key, object value,
EvictionReason reason, object state)
var message = $"Entry was evicted. Reason: reason.";
((HomeController)state)._cache.Set(_key, message);
2.5 设置缓存大小 SetSize
与SizeLimit
这里的缓存大小并不是通常意义上的多少KB、MB。而是一个没有单位的相对值,因为框架并不会去计算每个缓存项的大小。
如果通过SizeLimit
设置了总体缓存的大小,则必须通过SetSize
设置每一个缓存项的大小。
考虑以下的配置代码:
public class MyMemoryCache
public MemoryCache Cache get; private set;
public MyMemoryCache()
Cache = new MemoryCache(new MemoryCacheOptions
//设置总体缓存大小为600,无具体单位
SizeLimit = 600
);
然后,注入到容器:
public void ConfigureServices(IServiceCollection services)
services.AddRazorPages();
services.AddSingleton<MyMemoryCache>();
最后,设置每一个缓存项的大小:
var cacheEntryOptions = new MemoryCacheEntryOptions()
//设置此项大小为1
.SetSize(1)
.SetSlidingExpiration(TimeSpan.FromSeconds(3));
_cache.Set(MyKey, cacheEntry, cacheEntryOptions);
如果每一个缓存项的大小都设置为1
,则总体可以容纳600项,如果每个都是2,则可以容纳300项。
2.6 缓存依赖
缓存过期时,它的依赖项也会过期
public IActionResult CreateDependentEntries()
var cts = new CancellationTokenSource();
_cache.Set(CacheKeys.DependentCTS, cts);
using (var entry = _cache.CreateEntry(CacheKeys.Parent))
// expire this entry if the dependant entry expires.
entry.Value = DateTime.Now;
entry.RegisterPostEvictionCallback(DependentEvictionCallback, this);
_cache.Set(CacheKeys.Child,
DateTime.Now,
new CancellationChangeToken(cts.Token));
return RedirectToAction("GetDependentEntries");
public IActionResult GetDependentEntries()
return View("Dependent", new DependentViewModel
ParentCachedTime = _cache.Get<DateTime?>(CacheKeys.Parent),
ChildCachedTime = _cache.Get<DateTime?>(CacheKeys.Child),
Message = _cache.Get<string>(CacheKeys.DependentMessage)
);
public IActionResult RemoveChildEntry()
_cache.Get<CancellationTokenSource>(CacheKeys.DependentCTS).Cancel();
return RedirectToAction("GetDependentEntries");
private static void DependentEvictionCallback(object key, object value,
EvictionReason reason, object state)
var message = $"Parent entry was evicted. Reason: reason.";
((HomeController)state)._cache.Set(CacheKeys.DependentMessage, message);
2.7 其它说明
缓存过期不会在后台自动发生,当调用Get、Set、Remove
等方法是才会触发一次扫描过期缓存的操作。但是CancellationTokenSource
过期时也会触发这个操作。
public IActionResult CacheAutoExpiringTryGetValueSet()
DateTime cacheEntry;
if (!_cache.TryGetValue(CacheKeys.Entry, out cacheEntry))
cacheEntry = DateTime.Now;
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
var cacheEntryOptions = new MemoryCacheEntryOptions()
.AddExpirationToken(new CancellationChangeToken(cts.Token));
_cache.Set(CacheKeys.Entry, cacheEntry, cacheEntryOptions);
return View("Cache", cacheEntry);
3. 分布式缓存
这个就比较多了,有基于SqlServer的、有基于Redis的、有基于NCache的。
下节将会以Redis为例进行讲解。
https://docs.microsoft.com/zh-cn/aspnet/core/performance/caching/distributed?view=aspnetcore-6.0
引用:https://docs.microsoft.com/zh-cn/aspnet/core/performance/caching/response?view=aspnetcore-6.0
以上是关于在ASP.NET Core应用中使用IMemoryCache缓存的主要内容,如果未能解决你的问题,请参考以下文章
ASP.NET Core Web 应用程序系列- 在ASP.NET Core中使用Autofac替换自带DI进行批量依赖注入(MVC当中应用)
如何使用 EF Core 在 ASP.NET Core 中取消应用迁移
ASP.NET Core Web 应用程序系列- 在ASP.NET Core中使用Autofac替换自带DI进行构造函数和属性的批量依赖注入(MVC当中应用)
在 ASP.NET Core 应用程序中使用多个 HttpClient 对象
ASP.NET Core Web 应用程序系列- 在ASP.NET Core中使用Autofac替换自带DI进行构造函数和属性的批量依赖注入(MVC当中应用)