前言

    几乎在所有的应用程序中,缓存都是一个永恒的话题,恰当的使用缓存可以有效提高应用程序的性能;在某些业务场景下,使用缓存依赖会有很好的体验;在 Asp.Net Core 中,支持了多种缓存组件,这其中最基础也最易用的当属 IMemoryCache,该接口表示其存储依赖于托管程序服务器的内存,下面要介绍的内容就是基于 IMemoryCache 的缓存依赖。

1. IMemoryCache 的实现

Asp.Net Core 内部实现了一个继承自 IMemoryCache 接口的类 MemoryCache

这几乎已成惯例,一旦某个接口被列入 SDK 中,其必然包含了一个默认实现

1.1 使用 IMemoryCache

在 Asp.Net Core 中要使用 IMemoryCache 非常简单,只需要在 Startup 的 ConfigureServices 方法加入一句代码 services.AddMemoryCache() 即可

    public void ConfigureServices(IServiceCollection services)
{
services.AddMemoryCache();
...
}
1.2 在控制器中使用 IMemoryCache
    [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) 接口,获得下面的输出信息

  • 调用 Get() 接口

  • 调用 Get(int id) 接口

这看起来非常容易,几乎不用什么思考,你就学会了在 Asp.Net Core 中使用缓存,容易使用,这非常重要,这也是一门语言广泛推广的根本态度

2. 应用缓存策略

IMemoryCache 还包含了一个带参数的构造方法,让我们可以对缓存进行灵活的配置,该配置由类 MemoryCacheOptions 决定

2.1 MemoryCacheOptions 配置,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; }
}
  • ISystemClock:系统时钟,默认值为 null,官方文档对此属性没有说明,我也不知道是干什么用的,哪位大神求告知其作用和原理
  • ExpirationScanFrequency:对过期缓存的扫描间隔时间
  • SizeLimit:缓存区可存储记录条目数量
  • CompactionPercentage:在缓存过期策略生效的时候,对缓存进行压缩的百分比

上面的这个配置非常简单,在系统中应用类似下面的代码这样

 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

使用方法不变

2.1 单个键缓存策略

由于缓存的所有键其缓存过期优先级都是默认的 Normal,可能我们需要在某些业务场景下,让某些缓存值设置一个较高的优先级,比如设置永远都不过期,这样即使缓存达到最大限制条数以后也不会对其进行清理

  • 缓存优先级,该值为一个枚举类型,分别是 低、普通、高、永不移除,开发者可以根据不同的业务场景灵活设置
    public enum CacheItemPriority
{
Low = 0,
Normal = 1,
High = 2,
NeverRemove = 3
}
  • 设置策略,下面就使用 MemoryCacheEntryOptions 对单个键值进行应用策略
        [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 类

3. 使用缓存依赖策略

缓存依赖的意思是表示,一个或者多个缓存依赖于某个缓存,当某个缓存过期的时候,对其有依赖条件的其它缓存也会过期,在某些应用场景下,缓存依赖非常有用

3.1 创建 TokenController 并登录后注册依赖、获取缓存、移除缓存接口

以下示例使用一个模拟用户登录/登出的业务场景

    [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 项,此时,返回值为空

3.2 运行程序,分别调用 login/getkeys/logout 接口,分别得到以下输出结果
  • login 登录后注册依赖

  • getkeys 获取缓存

  • logout 移除缓存,尝试再次读取 CacheKeys 项,此时,返回值为空

  • 控制台输出移除通知(黄色字体部分信息)

可以看到,在用户登录登出这个业务场景下,使用缓存依赖项对其相关缓存进行管理,还是非常方便的,当用户退出登录后,即清空其所有相关缓存

结束语

  • 本文通过实例介绍了 IMemoryCache 的简单使用方法
  • 针对单个缓存键,也可以对其进行应用策略
  • 通过使用缓存依赖策略,可以在某些业务场景中有非常好的应用体验
  • 注意:当使用全局缓存策略 SizeLimit 时,每个键都需要设置一个大小
  • IMemoryCache 依赖于托管服务器等内存,一旦重启,缓存数据将立即被释放

示例代码下载

https://github.com/lianggx/EasyAspNetCoreDemo/tree/master/Ron.MemoryCacheDemo

Asp.Net Core 轻松学-在.Net Core 使用缓存和配置依赖策略的更多相关文章

  1. Asp.Net Core 轻松学-在.Net Core 中使用钩子

    前言     Host startup hook,是2.2中提供的一项新的功能,通过使用主机启动钩子,允许开发人员在不修改代码的情况下,在服务启动之前注入代码:通过使用钩子,可以对已部署好的服务在服务 ...

  2. Asp.Net Core 轻松学系列-1阅读指引目录

    https://www.cnblogs.com/viter/p/10474091.html 目录 前言 1. 从安装到配置 2. 业务实现 3. 日志 4. 测试 5. 缓存使用 6.网络和通讯 7. ...

  3. Asp.Net Core 轻松学-正确使用分布式缓存

    前言     本来昨天应该更新的,但是由于各种原因,抱歉,让追这个系列的朋友久等了.上一篇文章 在.Net Core 使用缓存和配置依赖策略 讲的是如何使用本地缓存,那么本篇文章就来了解一下如何使用分 ...

  4. Asp.Net Core 轻松学-使用MariaDB/MySql/PostgreSQL和支持多个上下文对象

    前言 在上一篇文章中(Asp.Net Core 轻松学-10分钟使用EFCore连接MSSQL数据库)[https://www.cnblogs.com/viter/p/10243577.html],介 ...

  5. Asp.Net Core 轻松学-多线程之Task(补充)

    前言     在上一章 Asp.Net Core 轻松学-多线程之Task快速上手 文章中,介绍了使用Task的各种常用场景,但是感觉有部分内容还没有完善,在这里补充一下. 1. 任务的等待 在使用 ...

  6. Asp.Net Core 轻松学-利用文件监视进行快速测试开发

    前言     在进行 Asp.Net Core 应用程序开发过程中,通常的做法是先把业务代码开发完成,然后建立单元测试,最后进入本地系统集成测试:在这个过程中,程序员的大部分时间几乎都花费在开发.运行 ...

  7. 如何从40亿整数中找到不存在的一个 webservice Asp.Net Core 轻松学-10分钟使用EFCore连接MSSQL数据库 WPF实战案例-打印 RabbitMQ与.net core(五) topic类型 与 headers类型 的Exchange

    如何从40亿整数中找到不存在的一个 前言 给定一个最多包含40亿个随机排列的32位的顺序整数的顺序文件,找出一个不在文件中的32位整数.(在文件中至少确实一个这样的数-为什么?).在具有足够内存的情况 ...

  8. WebAPI调用笔记 ASP.NET CORE 学习之自定义异常处理 MySQL数据库查询优化建议 .NET操作XML文件之泛型集合的序列化与反序列化 Asp.Net Core 轻松学-多线程之Task快速上手 Asp.Net Core 轻松学-多线程之Task(补充)

    WebAPI调用笔记   前言 即时通信项目中初次调用OA接口遇到了一些问题,因为本人从业后几乎一直做CS端项目,一个简单的WebAPI调用居然浪费了不少时间,特此记录. 接口描述 首先说明一下,基于 ...

  9. C# 中一些类关系的判定方法 C#中关于增强类功能的几种方式 Asp.Net Core 轻松学-多线程之取消令牌

    1.  IsAssignableFrom实例方法 判断一个类或者接口是否继承自另一个指定的类或者接口. public interface IAnimal { } public interface ID ...

随机推荐

  1. BZOJ3629(JLOI2014)聪明的燕姿

    (⊙﹏⊙)我交了好久,有坑啊...(如果没有匹配的话,即输出0种情况要记得换行...) 就是搜索,加上一点数论,并不太难... #include<cstdio> #include<c ...

  2. Https协议与HttpClient的实现

    一.背景 HTTP是一个传输内容有可读性的公开协议,客户端与服务器端的数据完全通过明文传输.在这个背景之下,整个依赖于Http协议的互联网数据都是透明的,这带来了很大的数据安全隐患.想要解决这个问题有 ...

  3. Java GC性能优化实战

    GC优化是必要的吗? 或者更准确地说,GC优化对Java基础服务来说是必要的吗?答案是否定的,事实上GC优化对Java基础服务来说在有些场合是可以省去的,但前提是这些正在运行的Java系统,必须包含以 ...

  4. 性能测试工具Locust的使用

    一.写在前面 官网:https://www.locust.io/ 官方使用文档:https://docs.locust.io/en/latest/ 大并发量测试时,建议在linux系统下进行. 二.L ...

  5. JavaScript引用类型之Array类型API详解

    Array类型也是ECMASCRIPT中最常见的数据类型,而且数据的每一项可以保存任何类型的数值,而且数组的大小是可以动态调整的,可以随着数据的添加自动增长以容纳新的数据.下面,总结数据的一些常用方法 ...

  6. MySSL HTTPS 评级 B 升 A+

    背景 MySSL 提供了免费的网站 HTTPS 安全评级服务,然后我用我的网站 https://hellogithub.com,测试了一下.发现安全评级为 B,最高为 A+.下面是记录我的网站从 B ...

  7. 内部类、异常以及 LeetCode 每日一题

    1 内部类 内部类的作用: 内部类提供了更好的封装,可以把内部类隐藏于外部类之内,不允许同一个包中的其他类访问该类.(例如给“牛”这个类组合一个“牛腿”,则可以把牛腿定义成内部类,因为牛腿脱离了牛没有 ...

  8. win10 DVWA下载安装配置(新手学渗透)

    电脑重装系统了,需要重新装一下渗透测试的学习环境DVWA,借此机会就跟大家讲一下DVWA的安装过程,因为不同的电脑配置.环境不同,在我的电脑上按照我这个安装教程是一次性就安装好了的.如果安装的时候遇到 ...

  9. solr搭建(linux)

    Solr版本:7.4.0 Tomcat版本:8.5 Jdk版本:1.8 最好在root用户下进行操作,为了更方便初学者理解,选用ubuntu操作,当然用命令操作过程是一样的,会命令操作的话看懂图形化操 ...

  10. svn 迁移至git操作手册

    svn 迁移至git操作手册 项目交付.版本管理工具变更等情况下,迁移svn旧历史记录有很大必要,方便后续追踪文件的提交历史,文件修改记录比对等.git自带了从svn迁移至git的工具命令,可很好的对 ...