作者:Rick Anderson, John Luo,和Steve Smith
通过减少生成内容所需的工作,缓存可以显著提高应用的性能和可伸缩性。 缓存最适用于不经常更改的数据,生成成本很高。 通过缓存,可以比从数据源返回的数据的副本速度快得多。 应该对应用进行编写和测试,使其永不依赖于缓存的数据。
ASP.NET Core 支持多种不同的缓存。 最简单的缓存基于IMemoryCache。 IMemoryCache
表示存储在 web 服务器的内存中的缓存。 使用内存中缓存时,在服务器场(多台服务器)上运行的应用应确保会话是粘滞的。 粘性会话可确保来自客户端的后续请求都转到同一台服务器。 例如,Azure Web 应用使用应用程序请求路由(ARR) 将所有的后续请求路由到同一台服务器。
Web 场中的非粘性会话需要分布式缓存以避免缓存一致性问题。 对于某些应用,分布式缓存可支持比内存中缓存更高的向外扩展。 使用分布式缓存可将缓存内存卸载到外部进程。
内存中缓存可以存储任何对象。 分布式缓存接口仅限 byte[]
。 内存中和分布式缓存将缓存项作为键值对。
System.Runtime.Caching/MemoryCache (NuGet 包)可用于:
建议对 System.Runtime.Caching
/MemoryCache
使用 Microsoft.Extensions.Caching.Memory/IMemoryCache
(本文中所述), 因为它更好地集成到 ASP.NET Core 中。 例如,IMemoryCache
与 ASP.NET Core依赖关系注入一起使用。
将 ASP.NET 4.x 中的代码移植到 ASP.NET Core 时,使用 System.Runtime.Caching
/MemoryCache
作为兼容性桥。
警告
使用依赖关系注入中的共享内存缓存并调用 SetSize
、Size
或 SizeLimit
来限制缓存大小可能会导致应用程序失败。 在缓存上设置大小限制时,在添加时,所有项都必须指定大小。 这可能会导致问题,因为开发人员可能无法完全控制使用共享缓存的内容。 例如,Entity Framework Core 使用共享缓存并且未指定大小。 如果应用设置了缓存大小限制并使用 EF Core,则应用将引发 InvalidOperationException
。
使用 SetSize
、Size
或 SizeLimit
限制缓存时,为缓存创建一个缓存单独。 有关详细信息和示例,请参阅使用 SetSize、Size 和 SizeLimit 限制缓存大小。
共享缓存由其他框架或库共享。 例如,EF Core 使用共享缓存并且未指定大小。
内存中缓存是从应用程序中使用依赖关系注入引用的一种服务。 在构造函数中请求 IMemoryCache
实例:
public class HomeController : Controller { private IMemoryCache _cache; public HomeController(IMemoryCache memoryCache) { _cache = memoryCache; }
以下代码使用TryGetValue来检查缓存中是否有时间。 如果未缓存时间,则将创建一个新条目,并将其设置为已添加到缓存中。 CacheKeys
类是下载示例的一部分。
public static class CacheKeys { public static string Entry { get { return "_Entry"; } } public static string CallbackEntry { get { return "_Callback"; } } public static string CallbackMessage { get { return "_CallbackMessage"; } } public static string Parent { get { return "_Parent"; } } public static string Child { get { return "_Child"; } } public static string DependentMessage { get { return "_DependentMessage"; } } public static string DependentCTS { get { return "_DependentCTS"; } } public static string Ticks { get { return "_Ticks"; } } public static string CancelMsg { get { return "_CancelMsg"; } } public static string CancelTokenSource { get { return "_CancelTokenSource"; } } }
public IActionResult CacheTryGetValueSet() { DateTime cacheEntry; // Look for cache key. if (!_cache.TryGetValue(CacheKeys.Entry, out cacheEntry)) { // Key not in cache, so get data. cacheEntry = DateTime.Now; // Set cache options. var cacheEntryOptions = new MemoryCacheEntryOptions() // Keep in cache for this time, reset time if accessed. .SetSlidingExpiration(TimeSpan.FromSeconds(3)); // Save data in cache. _cache.Set(CacheKeys.Entry, cacheEntry, cacheEntryOptions); } return View("Cache", cacheEntry); }
将会显示当前时间和缓存的时间:
@model DateTime? <div> <h2>Actions</h2> <ul> <li><a asp-controller="Home" asp-action="CacheTryGetValueSet">TryGetValue and Set</a></li> <li><a asp-controller="Home" asp-action="CacheGet">Get</a></li> <li><a asp-controller="Home" asp-action="CacheGetOrCreate">GetOrCreate</a></li> <li><a asp-controller="Home" asp-action="CacheGetOrCreateAsynchronous">CacheGetOrCreateAsynchronous</a></li> <li><a asp-controller="Home" asp-action="CacheRemove">Remove</a></li> <li><a asp-controller="Home" asp-action="CacheGetOrCreateAbs">CacheGetOrCreateAbs</a></li> <li><a asp-controller="Home" asp-action="CacheGetOrCreateAbsSliding">CacheGetOrCreateAbsSliding</a></li> </ul> </div> <h3>Current Time: @DateTime.Now.TimeOfDay.ToString()</h3> <h3>Cached Time: @(Model == null ? "No cached entry found" : Model.Value.TimeOfDay.ToString())</h3>
如果在超时期限内存在请求,则缓存 DateTime
值将保留在缓存中。
以下代码使用GetOrCreate和GetOrCreateAsync来缓存数据。
public IActionResult CacheGetOrCreate() { var cacheEntry = _cache.GetOrCreate(CacheKeys.Entry, entry => { entry.SlidingExpiration = TimeSpan.FromSeconds(3); return DateTime.Now; }); return View("Cache", cacheEntry); } public async Task<IActionResult> CacheGetOrCreateAsynchronous() { var cacheEntry = await _cache.GetOrCreateAsync(CacheKeys.Entry, entry => { entry.SlidingExpiration = TimeSpan.FromSeconds(3); return Task.FromResult(DateTime.Now); }); return View("Cache", cacheEntry); }
以下代码调用Get来提取缓存的时间:
public IActionResult CacheGet() { var cacheEntry = _cache.Get<DateTime?>(CacheKeys.Entry); return View("Cache", cacheEntry); }
下面的代码获取或创建具有绝对过期的缓存项:
public IActionResult CacheGetOrCreateAbs() { var cacheEntry = _cache.GetOrCreate(CacheKeys.Entry, entry => { entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(10); return DateTime.Now; }); return View("Cache", cacheEntry); }
只有具有可调过期的缓存项集存在过时的风险。 如果访问的时间比滑动过期时间间隔更频繁,则该项将永不过期。 将弹性过期与绝对过期组合在一起,以保证项目在其绝对过期时间通过后过期。 绝对过期会将项的上限设置为可缓存项的时间,同时仍允许项在可调整过期时间间隔内未请求时提前过期。 如果同时指定了绝对过期和可调过期时间,则过期时间以逻辑方式运算。 如果滑动过期时间间隔或绝对过期时间通过,则从缓存中逐出该项。
下面的代码获取或创建具有可调和绝对过期的缓存项:
public IActionResult CacheGetOrCreateAbsSliding() { var cacheEntry = _cache.GetOrCreate(CacheKeys.Entry, entry => { entry.SetSlidingExpiration(TimeSpan.FromSeconds(3)); entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(20); return DateTime.Now; }); return View("Cache", cacheEntry); }
前面的代码保证数据的缓存时间不超过绝对时间。
GetOrCreate、GetOrCreateAsync和 Get 是 CacheExtensions 类中的扩展方法。 这些方法扩展了 IMemoryCache的功能。
下面的示例执行以下操作:
public IActionResult CreateCallbackEntry() { var cacheEntryOptions = new MemoryCacheEntryOptions() // Pin to cache. .SetPriority(CacheItemPriority.NeverRemove) // Add eviction callback .RegisterPostEvictionCallback(callback: EvictionCallback, state: this); _cache.Set(CacheKeys.CallbackEntry, DateTime.Now, cacheEntryOptions); return RedirectToAction("GetCallbackEntry"); } public IActionResult GetCallbackEntry() { return View("Callback", new CallbackViewModel { CachedTime = _cache.Get<DateTime?>(CacheKeys.CallbackEntry), Message = _cache.Get<string>(CacheKeys.CallbackMessage) }); } public IActionResult RemoveCallbackEntry() { _cache.Remove(CacheKeys.CallbackEntry); 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(CacheKeys.CallbackMessage, message); }
MemoryCache
实例可以选择指定并强制实施大小限制。 缓存大小限制没有定义的度量单位,因为缓存没有度量条目大小的机制。 如果设置了缓存大小限制,则所有条目都必须指定 size。 ASP.NET Core 运行时不会根据内存压力限制缓存大小。 开发人员需要限制缓存大小。 指定的大小以开发人员选择的单位为单位。
例如:
如果未设置 SizeLimit,则缓存将不受限制。 当系统内存不足时,ASP.NET Core 运行时不会剪裁缓存。 应用必须构建为:
下面的代码创建一个无单位固定大小 MemoryCache 可通过依赖关系注入进行访问:
// using Microsoft.Extensions.Caching.Memory; public class MyMemoryCache { public MemoryCache Cache { get; set; } public MyMemoryCache() { Cache = new MemoryCache(new MemoryCacheOptions { SizeLimit = 1024 }); } }
SizeLimit
没有单位。 如果已设置缓存大小限制,则缓存条目必须以其认为最适合的任何单位指定大小。 缓存实例的所有用户都应使用同一单元系统。 如果缓存条目大小的总和超出 SizeLimit
指定的值,则不会缓存条目。 如果未设置任何缓存大小限制,则将忽略在该项上设置的缓存大小。
下面的代码向依赖关系注入容器注册 MyMemoryCache
。
public void ConfigureServices(IServiceCollection services) { services.AddRazorPages(); services.AddSingleton<MyMemoryCache>(); }
对于识别此大小限制缓存并知道如何适当设置缓存条目大小的组件,MyMemoryCache
创建为独立的内存缓存。
以下代码使用 MyMemoryCache
:
public class SetSize : PageModel { private MemoryCache _cache; public static readonly string MyKey = "_MyKey"; public SetSize(MyMemoryCache memoryCache) { _cache = memoryCache.Cache; } [TempData] public string DateTime_Now { get; set; } public IActionResult OnGet() { if (!_cache.TryGetValue(MyKey, out string cacheEntry)) { // Key not in cache, so get data. cacheEntry = DateTime.Now.TimeOfDay.ToString(); var cacheEntryOptions = new MemoryCacheEntryOptions() // Set cache entry size by extension method. .SetSize(1) // Keep in cache for this time, reset time if accessed. .SetSlidingExpiration(TimeSpan.FromSeconds(3)); // Set cache entry size via property. // cacheEntryOptions.Size = 1; // Save data in cache. _cache.Set(MyKey, cacheEntry, cacheEntryOptions); } DateTime_Now = cacheEntry; return RedirectToPage("./Index"); } }
缓存项的大小可以 Size 或 SetSize 扩展方法进行设置:
public IActionResult OnGet() { if (!_cache.TryGetValue(MyKey, out string cacheEntry)) { // Key not in cache, so get data. cacheEntry = DateTime.Now.TimeOfDay.ToString(); var cacheEntryOptions = new MemoryCacheEntryOptions() // Set cache entry size by extension method. .SetSize(1) // Keep in cache for this time, reset time if accessed. .SetSlidingExpiration(TimeSpan.FromSeconds(3)); // Set cache entry size via property. // cacheEntryOptions.Size = 1; // Save data in cache. _cache.Set(MyKey, cacheEntry, cacheEntryOptions); } DateTime_Now = cacheEntry; return RedirectToPage("./Index"); }
MemoryCache.Compact
尝试按以下顺序删除缓存的指定百分比:
永远不会删除优先级为 NeverRemove 的固定项。 以下代码将删除缓存项并调用 Compact
:
_cache.Remove(MyKey); // Remove 33% of cached items. _cache.Compact(.33); cache_size = _cache.Count;
有关详细信息,请参阅GitHub 上的 Compact 源。
以下示例演示在依赖项过期时如何使缓存项过期。 会将 CancellationChangeToken添加到缓存项。 在 Cancel
上调用 CancellationTokenSource
,时,这两个缓存条目都将被清除。
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); }
使用CancellationTokenSource可以将多个缓存条目作为一个组来清除。 使用上面代码中的 using
模式时using
块中创建的缓存条目会继承触发器和过期时间设置。
Get
、Set
、Remove
)都可以触发过期项的后台扫描。 CancellationTokenSource
(CancelAfter)上的计时器还会删除项,并触发扫描过期项。 下面的示例使用CancellationTokenSource (TimeSpan)作为已注册令牌。 此令牌激发后,会立即删除该条目,并激发逐出回调: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); }
使用回调重新填充缓存项时:
使用一个缓存条目创建另一个缓存条目时,子条目会复制父条目的过期令牌以及基于时间的过期设置。 手动删除或更新父项时,子级不会过期。
使用 PostEvictionCallbacks 设置从缓存中逐出缓存项后将触发的回调。
对于大多数应用,IMemoryCache
已启用。 例如,在 Add{Service}
中调用 AddMvc
、AddControllersWithViews
、AddRazorPages
、AddMvcCore().AddRazorViewEngine
以及许多其他 ConfigureServices
方法会启用 IMemoryCache
。 对于未调用上述某个 Add{Service}
方法的应用,可能需要在 ConfigureServices
调用 AddMemoryCache。
作者:Rick Anderson, John Luo,和Steve Smith
通过减少生成内容所需的工作,缓存可以显著提高应用的性能和可伸缩性。 缓存对不经常更改的数据效果最佳。 缓存生成的数据副本的返回速度可以比从原始源返回更快。 应编写并测试代码,使其绝不会依赖于缓存的数据。
ASP.NET Core 支持多种不同的缓存。 最简单的缓存基于 IMemoryCache,它表示存储在 Web 服务器内存中的缓存。 在服务器场中运行的应用(多台服务器)应确保会话在使用内存中缓存时处于粘滞。 粘滞会话确保以后来自客户端的请求都发送到相同的服务器。 例如,Azure Web 应用使用应用程序请求路由(ARR)将来自用户代理的所有请求路由到同一服务器。
Web 场中的非粘性会话需要分布式缓存以避免缓存一致性问题。 对于某些应用,分布式缓存可支持比内存中缓存更高的向外扩展。 使用分布式缓存可将缓存内存卸载到外部进程。
内存中缓存可以存储任何对象。 分布式缓存接口仅限 byte[]
。 内存中和分布式缓存将缓存项作为键值对。
System.Runtime.Caching/MemoryCache (NuGet 包)可用于:
建议对 System.Runtime.Caching
/MemoryCache
使用 Microsoft.Extensions.Caching.Memory/IMemoryCache
(本文中所述), 因为它更好地集成到 ASP.NET Core 中。 例如,IMemoryCache
与 ASP.NET Core依赖关系注入一起使用。
将 ASP.NET 4.x 中的代码移植到 ASP.NET Core 时,使用 System.Runtime.Caching
/MemoryCache
作为兼容性桥。
警告
使用依赖关系注入中的共享内存缓存并调用 SetSize
、Size
或 SizeLimit
来限制缓存大小可能会导致应用程序失败。 在缓存上设置大小限制时,在添加时,所有项都必须指定大小。 这可能会导致问题,因为开发人员可能无法完全控制使用共享缓存的内容。 例如,Entity Framework Core 使用共享缓存并且未指定大小。 如果应用设置了缓存大小限制并使用 EF Core,则应用将引发 InvalidOperationException
。
使用 SetSize
、Size
或 SizeLimit
限制缓存时,为缓存创建一个缓存单独。 有关详细信息和示例,请参阅使用 SetSize、Size 和 SizeLimit 限制缓存大小。
内存中缓存是使用依赖关系注入从应用中引用的服务。 请在ConfigureServices
中调用AddMemoryCache
:
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddMemoryCache(); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); } public void Configure(IApplicationBuilder app) { app.UseMvcWithDefaultRoute(); } }
在构造函数中请求 IMemoryCache
实例:
public class HomeController : Controller { private IMemoryCache _cache; public HomeController(IMemoryCache memoryCache) { _cache = memoryCache; }
IMemoryCache
需要 NuGet 包Microsoft.Extensions.Caching.Memory, 此包可在Microsoft.AspNetCore.App metapackage中找到的。
以下代码使用TryGetValue来检查缓存中是否有时间。 如果未缓存时间,则将创建一个新条目,并将其设置为已添加到缓存中。
public static class CacheKeys { public static string Entry { get { return "_Entry"; } } public static string CallbackEntry { get { return "_Callback"; } } public static string CallbackMessage { get { return "_CallbackMessage"; } } public static string Parent { get { return "_Parent"; } } public static string Child { get { return "_Child"; } } public static string DependentMessage { get { return "_DependentMessage"; } } public static string DependentCTS { get { return "_DependentCTS"; } } public static string Ticks { get { return "_Ticks"; } } public static string CancelMsg { get { return "_CancelMsg"; } } public static string CancelTokenSource { get { return "_CancelTokenSource"; } } }
public IActionResult CacheTryGetValueSet() { DateTime cacheEntry; // Look for cache key. if (!_cache.TryGetValue(CacheKeys.Entry, out cacheEntry)) { // Key not in cache, so get data. cacheEntry = DateTime.Now; // Set cache options. var cacheEntryOptions = new MemoryCacheEntryOptions() // Keep in cache for this time, reset time if accessed. .SetSlidingExpiration(TimeSpan.FromSeconds(3)); // Save data in cache. _cache.Set(CacheKeys.Entry, cacheEntry, cacheEntryOptions); } return View("Cache", cacheEntry); }
将会显示当前时间和缓存的时间:
@model DateTime? <div> <h2>Actions</h2> <ul> <li><a asp-controller="Home" asp-action="CacheTryGetValueSet">TryGetValue and Set</a></li> <li><a asp-controller="Home" asp-action="CacheGet">Get</a></li> <li><a asp-controller="Home" asp-action="CacheGetOrCreate">GetOrCreate</a></li> <li><a asp-controller="Home" asp-action="CacheGetOrCreateAsync">GetOrCreateAsync</a></li> <li><a asp-controller="Home" asp-action="CacheRemove">Remove</a></li> </ul> </div> <h3>Current Time: @DateTime.Now.TimeOfDay.ToString()</h3> <h3>Cached Time: @(Model == null ? "No cached entry found" : Model.Value.TimeOfDay.ToString())</h3>
如果在超时期限内存在请求,则缓存 DateTime
值将保留在缓存中。 下图显示当前时间以及从缓存中检索的较早时间:
以下代码使用GetOrCreate和GetOrCreateAsync来缓存数据。
public IActionResult CacheGetOrCreate() { var cacheEntry = _cache.GetOrCreate(CacheKeys.Entry, entry => { entry.SlidingExpiration = TimeSpan.FromSeconds(3); return DateTime.Now; }); return View("Cache", cacheEntry); } public async Task<IActionResult> CacheGetOrCreateAsync() { var cacheEntry = await _cache.GetOrCreateAsync(CacheKeys.Entry, entry => { entry.SlidingExpiration = TimeSpan.FromSeconds(3); return Task.FromResult(DateTime.Now); }); return View("Cache", cacheEntry); }
以下代码调用Get来提取缓存的时间:
public IActionResult CacheGet() { var cacheEntry = _cache.Get<DateTime?>(CacheKeys.Entry); return View("Cache", cacheEntry); }
GetOrCreate、GetOrCreateAsync和Get是扩展方法的一部分,扩展方法是扩展 IMemoryCache功能的CacheExtensions类的一部分。 有关其他缓存方法的说明,请参阅IMemoryCache 方法和CacheExtensions 方法。
下面的示例执行以下操作:
CacheItemPriority.NeverRemove
。public IActionResult CreateCallbackEntry() { var cacheEntryOptions = new MemoryCacheEntryOptions() // Pin to cache. .SetPriority(CacheItemPriority.NeverRemove) // Add eviction callback .RegisterPostEvictionCallback(callback: EvictionCallback, state: this); _cache.Set(CacheKeys.CallbackEntry, DateTime.Now, cacheEntryOptions); return RedirectToAction("GetCallbackEntry"); } public IActionResult GetCallbackEntry() { return View("Callback", new CallbackViewModel { CachedTime = _cache.Get<DateTime?>(CacheKeys.CallbackEntry), Message = _cache.Get<string>(CacheKeys.CallbackMessage) }); } public IActionResult RemoveCallbackEntry() { _cache.Remove(CacheKeys.CallbackEntry); 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(CacheKeys.CallbackMessage, message); }
MemoryCache
实例可以选择指定并强制实施大小限制。 缓存大小限制没有定义的度量单位,因为缓存没有度量条目大小的机制。 如果设置了缓存大小限制,则所有条目都必须指定 size。 ASP.NET Core 运行时不会根据内存压力限制缓存大小。 开发人员需要限制缓存大小。 指定的大小以开发人员选择的单位为单位。
例如:
如果未设置 SizeLimit,则缓存将不受限制。 当系统内存不足时,ASP.NET Core 运行时不会剪裁缓存。 应用程序的体系结构非常多:
下面的代码创建一个无单位固定大小 MemoryCache 可通过依赖关系注入进行访问:
// using Microsoft.Extensions.Caching.Memory; public class MyMemoryCache { public MemoryCache Cache { get; set; } public MyMemoryCache() { Cache = new MemoryCache(new MemoryCacheOptions { SizeLimit = 1024 }); } }
SizeLimit
没有单位。 如果已设置缓存大小限制,则缓存条目必须以其认为最适合的任何单位指定大小。 缓存实例的所有用户都应使用同一单元系统。 如果缓存条目大小的总和超出 SizeLimit
指定的值,则不会缓存条目。 如果未设置任何缓存大小限制,则将忽略在该项上设置的缓存大小。
下面的代码向依赖关系注入容器注册 MyMemoryCache
。
public void ConfigureServices(IServiceCollection services) { services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); services.AddSingleton<MyMemoryCache>(); }
对于识别此大小限制缓存并知道如何适当设置缓存条目大小的组件,MyMemoryCache
创建为独立的内存缓存。
以下代码使用 MyMemoryCache
:
public class AboutModel : PageModel { private MemoryCache _cache; public static readonly string MyKey = "_MyKey"; public AboutModel(MyMemoryCache memoryCache) { _cache = memoryCache.Cache; } [TempData] public string DateTime_Now { get; set; } public IActionResult OnGet() { if (!_cache.TryGetValue(MyKey, out string cacheEntry)) { // Key not in cache, so get data. cacheEntry = DateTime.Now.TimeOfDay.ToString(); var cacheEntryOptions = new MemoryCacheEntryOptions() // Set cache entry size by extension method. .SetSize(1) // Keep in cache for this time, reset time if accessed. .SetSlidingExpiration(TimeSpan.FromSeconds(3)); // Set cache entry size via property. // cacheEntryOptions.Size = 1; // Save data in cache. _cache.Set(MyKey, cacheEntry, cacheEntryOptions); } DateTime_Now = cacheEntry; return RedirectToPage("./Index"); } }
public IActionResult OnGet() { if (!_cache.TryGetValue(MyKey, out string cacheEntry)) { // Key not in cache, so get data. cacheEntry = DateTime.Now.TimeOfDay.ToString(); var cacheEntryOptions = new MemoryCacheEntryOptions() // Set cache entry size by extension method. .SetSize(1) // Keep in cache for this time, reset time if accessed. .SetSlidingExpiration(TimeSpan.FromSeconds(3)); // Set cache entry size via property. // cacheEntryOptions.Size = 1; // Save data in cache. _cache.Set(MyKey, cacheEntry, cacheEntryOptions); } DateTime_Now = cacheEntry; return RedirectToPage("./Index"); }
MemoryCache.Compact
尝试按以下顺序删除缓存的指定百分比:
永远不会删除优先级为 NeverRemove 的固定项。
_cache.Remove(MyKey); // Remove 33% of cached items. _cache.Compact(.33); cache_size = _cache.Count;
有关详细信息,请参阅GitHub 上的 Compact 源。
以下示例演示在依赖项过期时如何使缓存项过期。 会将 CancellationChangeToken添加到缓存项。 在 Cancel
上调用 CancellationTokenSource
,时,这两个缓存条目都将被清除。
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); }
使用CancellationTokenSource
可以将多个缓存条目作为一个组来清除。 使用上面代码中的 using
模式时using
块中创建的缓存条目会继承触发器和过期时间设置。
使用回调重新填充缓存项时:
使用一个缓存条目创建另一个缓存条目时,子条目会复制父条目的过期令牌以及基于时间的过期设置。 手动删除或更新父项时,子级不会过期。
使用PostEvictionCallbacks设置从缓存中逐出缓存项后将触发的回调。