C#系列之聊聊.Net Core的InMemoryCache
作者:暴王
个人博客:http://www.boydwang.com/2017/12/net-core-in-memory-cache/
这两天在看.net core的in memory cache,这里记录一下用法,主要涉及MemoryCache的Get/Set/Expire/Flush。
首先我们先用dotnet命令创建一个mvc的项目,这里我们将使用postman来请求server,
dotnet new MVC
因为我们要用到 Microsoft.Extensions.Caching.Memory这个nuget包,所以需要添加引用,用VsCode(或任何编辑器)打开刚才建的mvc项目路径下的*.csproj文件,在这里我的是cache.csproj,找到这个标签,添加如下代码:
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="2.0.0.0"/>
注意版本号可能不一样,我用的是.net core 2.0.
之后我们需要注册cache服务,打开Startup.cs文件,找到ConfigureServices方法,添加如下代码:
services.AddMemoryCache();
ConfigureServices方法看起来应该是这样:
public void ConfigureServices(IServiceCollection services)
{
services.AddMemoryCache();
services.AddMvc();
}
之后我们就可以在controller里通过构造注入的方式使用InMemoryCache啦。
打开HomeController或者自己新建一个Controller,在修改构造方法
private IMemoryCache _cache;
public HomeController(IMemoryCache cache)
{
this._cache = cache;
}
先来看看MemoryCache的定义:
Constructors:
MemoryCache(IOptions)
Properties:
Count(Gets the count of the current entries for diagnostic purposes.)
Methods:
Compact(Double)
CreateEntry(Object)
Dispose()
Dispose(Boolean)
Finalize()
Remove(Object)
TryGetValue(Object, Object)
Extension Methods:
Get(IMemoryCache, Object)
Get(IMemoryCache, Object)
GetOrCreate(IMemoryCache, Object, Func)
GetOrCreateAsync(IMemoryCache, Object, Func>)
Set(IMemoryCache, Object, TItem)
Set(IMemoryCache, Object, TItem, MemoryCacheEntryOptions)
Set(IMemoryCache, Object, TItem, IChangeToken)
Set(IMemoryCache, Object, TItem, DateTimeOffset)
Set(IMemoryCache, Object, TItem, TimeSpan)
TryGetValue(IMemoryCache, Object, TItem)
我们用到的大部分都是 扩 展 方 法,这是一个奇怪的现象,但这不是这篇文章讨论的重点,这里会使用到
TryGetValue(Object, Object)
Set<TItem>(IMemoryCache, Object, TItem, MemoryCacheEntryOptions)
这两个方法,来Get/Set/Expire缓存项。
首先我们来添加一个get的webapi:
[HttpGet("cache/{key}")]
public IActionResult GetCache(string key)
{
object result = new object();
_cache.TryGetValue(key, out result);
return new JsonResult(result);
}
它接受一个key作为参数,如果找到则返回找到的值,若找不到则返回空
现在我们可以在命令行里输入
dotnet restore
dotnet run
来启动web项目,之后我们可以通过
http://localhost:5000/cache/{key}
这个url来访问cache,此时cache还没有值
因为此时我们还没有set值。
接下来添加一个Set方法,在添加之前,我们先来看一下MemoryCacheEntryOptions的定义。
Constructors:
MemoryCacheEntryOptions()
Properties:
AbsoluteExpiration
AbsoluteExpirationRelativeToNow
ExpirationTokens
PostEvictionCallbacks
Priority
Size
SlidingExpiration
Extension Methods:
AddExpirationToken(MemoryCacheEntryOptions, IChangeToken)
RegisterPostEvictionCallback(MemoryCacheEntryOptions, PostEvictionDelegate)
RegisterPostEvictionCallback(MemoryCacheEntryOptions, PostEvictionDelegate, Object)
SetAbsoluteExpiration(MemoryCacheEntryOptions, DateTimeOffset)
SetAbsoluteExpiration(MemoryCacheEntryOptions, TimeSpan)
SetPriority(MemoryCacheEntryOptions, CacheItemPriority)
SetSize(MemoryCacheEntryOptions, Int64)
SetSlidingExpiration(MemoryCacheEntryOptions, TimeSpan)
这里有几个概念:
AbsoluteExpiration
代表了绝对绝对超时时间,在一定时间后必定超时(比如15分钟)
SlidingExpiration
代表了滑动超时时间(我自己翻译的。。),滑动的意思就是假如你设置了SlidingExpiration超时时间为5分钟,如果在5分钟里,有新的请求来获取这个cached item,那么这个5分钟会重置,直到超过5分钟没有请求来,才超时
CacheItemPriority
这是一个枚举,代表了缓存的优先级,默认值为Normal,如果设置为NeverRemove则一直不超时。
High
Low
NeverRemove
Normal
RegisterPostEvictionCallback
这是个方法需要传一个回调,在缓存项被移除(超时)的时候触发回调。
接着我们来添加一个Set方法,并且为它添加一个canceltoken,以便我们能够手动控制强制清空缓存。
private static CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
[HttpPost("cache/")]
public IActionResult SetCache([FromBody]CacheItem item)
{
var cacheEntryOptions = new MemoryCacheEntryOptions()
.SetAbsoluteExpiration(TimeSpan.FromMinutes(5))
.RegisterPostEvictionCallback(DependentEvictionCallback, null)
.AddExpirationToken(new CancellationChangeToken(cancellationTokenSource.Token));
_cache.Set(item.key, item.value, cacheEntryOptions);
return Ok();
}
然后我们就可以用postman的post请求来Set缓存了,地址是:
http://localhost:5000/cache
接下来我们来添加一个flush api,我们能够手动清空缓存。这里我们利用了上面在Set时添加的cancellationTokenSource
[HttpGet("cache/flush")]
public IActionResult Flush()
{
cancellationTokenSource.Cancel();
return Ok();
}
访问地址:
http://localhost:5000/cache/flush
调用这个api会发现在console里有一行输出
Parent entry was evicted. Reason: TokenExpired, Key: a.
可以在多个缓存项中添加同一个token,达到同时清除多个缓存项的目的。
遇到的坑:
1.token不work的问题.
我在最初实现的时候,加了一个token,是这么写的
private CancellationTokenSource cancellationTokenSource;
public HomeController(IMemoryCache cache)
{
this._cache = cache;
cancellationTokenSource = new CancellationTokenSource();
}
[HttpGet("cache/flush")]
public IActionResult Flush()
{
cancellationTokenSource.Cancel();
return Ok();
}
然后发现调用flush一直不生效,cache并没有被清掉,很纳闷,以为我的token方法用的有问题。
直到我换成了下面的代码,大家体会一下。
private static CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
public HomeController(IMemoryCache cache)
{
this._cache = cache;
}
[HttpGet("cache/flush")]
public IActionResult Flush()
{
cancellationTokenSource.Cancel();
return Ok();
}
仅仅是一个static的问题,就产生了不一样的结果,这是因为每次httprequest过来,都会启动一个新线程去响应它,因此在set的时候加进去的那个token,并不是flush请求过来的token,因为又调用了一次构造方法,生成了一个新的CancellationTokenSource对象,因此调用token.Cancel()方法必然会失效,因此改成了static,让每次请求的都是同一个token,这样就不会造成不同token导致的Cancel方法不work的问题,清空cache也就能正常工作了。
2.RegisterPostEvictionCallback重复触发的问题
RegisterPostEvictionCallback不仅仅在缓存超时的时候触发,也会在缓存被替换(更新)的时候触发,在PostEvictionDelegate有一个参数为EvictionReason指明了缓存项被移除的原因
public delegate void PostEvictionDelegate(object key, object value, EvictionReason reason, object state);
EvictionReason
None = 0,
Removed = 1, 缓存项被Remove()方法移除
Replaced = 2, 缓存项被更新
Expired = 3, 缓存项超时
TokenExpired = 4, 缓存由token触发超时
Capacity = 5 缓存空间不足
因此我们需要在callback里根据需要判断缓存是因为什么原因被移除,才能避免意外的回调触发。
C#系列之聊聊.Net Core的InMemoryCache的更多相关文章
- 学习ASP.NET Core Razor 编程系列五——Asp.Net Core Razor新建模板页面
学习ASP.NET Core Razor 编程系列目录 学习ASP.NET Core Razor 编程系列一 学习ASP.NET Core Razor 编程系列二——添加一个实体 学习ASP.NET ...
- C#中的函数式编程:递归与纯函数(二) 学习ASP.NET Core Razor 编程系列四——Asp.Net Core Razor列表模板页面
C#中的函数式编程:递归与纯函数(二) 在序言中,我们提到函数式编程的两大特征:无副作用.函数是第一公民.现在,我们先来深入第一个特征:无副作用. 无副作用是通过引用透明(Referential ...
- 学习ASP.NET Core Razor 编程系列四——Asp.Net Core Razor列表模板页面
学习ASP.NET Core Razor 编程系列目录 学习ASP.NET Core Razor 编程系列一 学习ASP.NET Core Razor 编程系列二——添加一个实体 学习ASP.NET ...
- 《ASP.NET Core In Action》读书笔记系列五 ASP.NET Core 解决方案结构解析1
创建好项目后,解决方案资源管理器窗口里我们看到,增加了不少文件夹及文件,如下图所示: 在解决方案文件夹中,找到项目文件夹,该文件夹又包含五个子文件夹 -Models.Controllers.Views ...
- 《ASP.NET Core In Action》读书笔记系列三 ASP.NET Core如何处理请求的?
在本节中,您将看到ASP.NET Core应用程序如何运行的,从请求URL开始到页面呈现在浏览器中. 为此,您将看到 一个HTTP请求在Web服务器中是如何被处理的.ASP.NET Core如何扩展该 ...
- 《ASP.NET Core In Action》读书笔记系列二 ASP.NET Core 能用于什么样的应用,什么时候选择ASP.NET Core
ASP.NET Core 能用于什么样的应用 ASP.NET Core 可以用作传统的web服务.RESTful服务.远程过程调用(RPC)服务.微服务,这归功于它的跨平台支持和轻量级设计.如下图所示 ...
- 《ASP.NET Core In Action》读书笔记系列一 ASP.NET Core 的诞生
最近打算系统学习一下asp.net core ,苦于没有好的中文书藉,只好找来一本英文的 <ASP.NET Core In Action>学习.我和多数人一样,学习英文会明显慢于中文.希 ...
- StreamSets学习系列之StreamSets的Core Tarball方式安装(图文详解)
不多说,直接上干货! 前期博客 StreamSets学习系列之StreamSets支持多种安装方式[Core Tarball.Cloudera Parcel .Full Tarball .Full R ...
- 《ASP.NET Core 高性能系列》关于.NET Core的配置信息的若干事项
1.配置文件的相关闲话 Core自身对于配置文件不是必须品,但由上文分析可知ASP.NET Core默认采用appsettings.json作为配置文件,关于配置信息的优先等级 命令行>环境变量 ...
随机推荐
- flink引出的kafka不同版本的兼容性
参考: 官网协议介绍:http://kafka.apache.org/protocol.html#The_Messages_Fetch kafka协议兼容性 http://www.cnblogs.c ...
- 28. 实现strStr()
实现 strStr() 函数. 给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始).如果不存在,则返 ...
- [ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.2:compile (default-compile) on project taotao-manager-pojo: Compilation failure
运行maven项目时报错 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.2:compi ...
- spring深入学习(四)-----spring aop
AOP概述 aop其实就是面向切面编程,举个例子,比如项目中有n个方法是对外提供http服务的,那么如果我需要对这些http服务进行响应时间的监控,按照传统的方式就是每个方法中添加相应的逻辑,但是这些 ...
- 解决更新ssh后在/etc/init.d下无sshd的问题
1.将远程服务器的/etc/init.d/ssd 文件拷贝到本地 scp /etc/init.d/ssh root@IP地址:/etc/init.d 2.vi /etc/init.d/sshd 3 ...
- docker部署pinpoint
pinpoint-collector部署 Dockerfile FROM tomcat8:jdk8 MAINTAINER limugen<limugen@uce.cn> ENV APP_H ...
- Day04 (黑客成长日记) 集合记录
集合 集合:是可变的数据类型 ,它里面的数据类型必须是不可变的数据类型,无序,不重复,不同于字典,他有元素,没有键值对(编码不常用) li = set([1,2,3]) li = {'alex','w ...
- 初识 Proxysql
1.ProxySQL 介绍和安装 ProxySQL 是一种高性能.高可用的开源中间件,适用于mysql和相关的数据库,如MariaDB官网:http://www.proxysql.com 安装 发行版 ...
- 基于ajax提交数据
昨日回顾: 1 inclusion_tag -干什么用的?生成html的片段(动态,传参数,传数据) -app下新建一个模块,templatetags -创建一个py文件(mytag.py) -fro ...
- python_flask 基础巩固 (DEBUG模式)
默认情况下flask不会开启DEBUG模式,开启DEBUG模式后,flask会在每次保存代码的时候自动的重新载入代码,并且如果代码有错误,会在终端进行提示. 开启DEBUG模式有四种方式: 1.直接在 ...