几乎在全部的应用程序中,缓存都是一个永恒的话题,恰当的使用缓存能够有效提升应用程序的性能;在某些业务场景下,使用缓存依赖会有很好的体验;在 Asp.Net Core 中,支持了多种缓存组件,这其中最基础也最易用的当属 IMemoryCache,该接口表示其存储依赖于托管程序服务器的内存,下面要介绍的内容就是基于 IMemoryCache 的缓存依赖。git
Asp.Net Core 内部实现了一个继承自 IMemoryCache 接口的类 MemoryCache
这几乎已成惯例,一旦某个接口被列入 SDK 中,其必然包含了一个默认实现github
在 Asp.Net Core 中要使用 IMemoryCache 很是简单,只须要在 Startup 的 ConfigureServices 方法加入一句代码 services.AddMemoryCache() 便可api
public void ConfigureServices(IServiceCollection services) { services.AddMemoryCache(); ... }
[Route("api/[controller]")] [ApiController] public class HomeController : ControllerBase { private IMemoryCache cache; public HomeController(IMemoryCache cache) { this.cache = cache; } [HttpGet] public ActionResult<IEnumerable<string>> Get() { cache.Set("userId", "0001"); return new string[] { "value1", "value2" }; } [HttpGet("{id}")] public ActionResult<string> Get(int id) { return cache.Get<string>("userId"); } }
上面的代码表示在 HomeController 控制器的构造方法中使用注入的方式得到了一个 IMemoryCache 对象,在 Get() 方法中增长了一条缓存记录 "userId=0001",而后在 Get(int id) 接口中提取该缓存记录
运行程序,分别调用 Get() 和 Get(int id) 接口,得到下面的输出信息缓存
这看起来很是容易,几乎不用什么思考,你就学会了在 Asp.Net Core 中使用缓存,容易使用,这很是重要,这也是一门语言普遍推广的根本态度服务器
IMemoryCache 还包含了一个带参数的构造方法,让咱们能够对缓存进行灵活的配置,该配置由类 MemoryCacheOptions 决定异步
public class MemoryCacheOptions : IOptions<MemoryCacheOptions> { public MemoryCacheOptions(); public ISystemClock Clock { get; set; } [Obsolete("This is obsolete and will be removed in a future version.")] public bool CompactOnMemoryPressure { get; set; } public TimeSpan ExpirationScanFrequency { get; set; } public long? SizeLimit { get; set; } public double CompactionPercentage { get; set; } }
上面的这个配置很是简单,在系统中应用相似下面的代码这样性能
public void ConfigureServices(IServiceCollection services) { services.AddMemoryCache(options => { options.CompactionPercentage = 0.02d; options.ExpirationScanFrequency = TimeSpan.FromMinutes(5); options.SizeLimit = 1024; }); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); }
上面的缓存策略设置为缓存压缩比为 2%,每 5 分钟进行一次过时缓存的扫描,最大缓存空间大小限制为 1024
使用方法不变字体
因为缓存的全部键其缓存过时优先级都是默认的 Normal,可能咱们须要在某些业务场景下,让某些缓存值设置一个较高的优先级,好比设置永远都不过时,这样即便缓存达到最大限制条数之后也不会对其进行清理this
public enum CacheItemPriority { Low = 0, Normal = 1, High = 2, NeverRemove = 3 }
[HttpGet] public ActionResult<IEnumerable<string>> Get() { MemoryCacheEntryOptions entry = new MemoryCacheEntryOptions { Priority = CacheItemPriority.NeverRemove }; cache.Set("userId", "0001", entry); return new string[] { "value1", "value2" }; }
上面的代码表示,咱们对缓存键 "userId" 应用了一个 “永不移除” 的策略,固然,还能够对单个值作很是多的策略,好比如今 "userId" 的值大小等等,有兴趣的同窗能够深刻了解 MemoryCacheEntryOptions 类code
缓存依赖的意思是表示,一个或者多个缓存依赖于某个缓存,当某个缓存过时的时候,对其有依赖条件的其它缓存也会过时,在某些应用场景下,缓存依赖很是有用
如下示例使用一个模拟用户登陆/登出的业务场景
[Route("api/[controller]")] [ApiController] public class TokenController : ControllerBase { private IMemoryCache cache; public TokenController(IMemoryCache cache) { this.cache = cache; } // 建立注册依赖 [HttpGet("login")] public ActionResult<string> Login() { var cts = new CancellationTokenSource(); cache.Set(CacheKeys.DependentCTS, cts); using (var entry = cache.CreateEntry(CacheKeys.UserSession)) { entry.Value = "_x0123456789"; entry.RegisterPostEvictionCallback(DependentEvictionCallback, this); cache.Set(CacheKeys.UserShareData, "这里是共享的数据", new CancellationChangeToken(cts.Token)); cache.Set(CacheKeys.UserCart, "这里是购物车", new CancellationChangeToken(cts.Token)); } return "设置依赖完成"; } // 获取缓存 [HttpPost("getkeys")] public IActionResult GetKeys() { var userInfo = new { UserSession = cache.Get<string>(CacheKeys.UserSession), UserShareData = cache.Get<string>(CacheKeys.UserShareData), UserCart = cache.Get<string>(CacheKeys.UserCart) }; return new JsonResult(userInfo); } // 移除缓存 [HttpPost("logout")] public ActionResult<string> LogOut() { cache.Get<CancellationTokenSource>(CacheKeys.DependentCTS).Cancel(); var userInfo = new { UserSession = cache.Get<string>(CacheKeys.UserSession), UserShareData = cache.Get<string>(CacheKeys.UserShareData), UserCart = cache.Get<string>(CacheKeys.UserCart) }; return new JsonResult(userInfo); } // 过时通知 private static void DependentEvictionCallback(object key, object value, EvictionReason reason, object state) { Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine("Key:{0} 已过时,依赖于该 Key 的全部缓存都将过时而处于不可用状态", key); Console.ForegroundColor = ConsoleColor.Gray; } }
上面的代码使用 CancellationTokenSource 用做事件通知源,当移除 CacheKeys.DependentCTS 并触发 CancellationTokenSource.Cancel() 方法后,将异步触发 DependentEvictionCallback(object key, object value, EvictionReason reason, object state)委托;此时,托管程序收到一个通知,用户已登出,已移除用户相关缓存,任何移除接口尝试再次读取 CacheKeys 项,此时,返回值为空
能够看到,在用户登陆登出这个业务场景下,使用缓存依赖项对其相关缓存进行管理,仍是很是方便的,当用户退出登陆后,即清空其全部相关缓存
https://github.com/lianggx/EasyAspNetCoreDemo/tree/master/Ron.MemoryCacheDemo