作者:暴王

个人博客: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的更多相关文章

  1. 学习ASP.NET Core Razor 编程系列五——Asp.Net Core Razor新建模板页面

    学习ASP.NET Core Razor 编程系列目录 学习ASP.NET Core Razor 编程系列一 学习ASP.NET Core Razor 编程系列二——添加一个实体 学习ASP.NET ...

  2. C#中的函数式编程:递归与纯函数(二) 学习ASP.NET Core Razor 编程系列四——Asp.Net Core Razor列表模板页面

    C#中的函数式编程:递归与纯函数(二)   在序言中,我们提到函数式编程的两大特征:无副作用.函数是第一公民.现在,我们先来深入第一个特征:无副作用. 无副作用是通过引用透明(Referential ...

  3. 学习ASP.NET Core Razor 编程系列四——Asp.Net Core Razor列表模板页面

    学习ASP.NET Core Razor 编程系列目录 学习ASP.NET Core Razor 编程系列一 学习ASP.NET Core Razor 编程系列二——添加一个实体 学习ASP.NET ...

  4. 《ASP.NET Core In Action》读书笔记系列五 ASP.NET Core 解决方案结构解析1

    创建好项目后,解决方案资源管理器窗口里我们看到,增加了不少文件夹及文件,如下图所示: 在解决方案文件夹中,找到项目文件夹,该文件夹又包含五个子文件夹 -Models.Controllers.Views ...

  5. 《ASP.NET Core In Action》读书笔记系列三 ASP.NET Core如何处理请求的?

    在本节中,您将看到ASP.NET Core应用程序如何运行的,从请求URL开始到页面呈现在浏览器中. 为此,您将看到 一个HTTP请求在Web服务器中是如何被处理的.ASP.NET Core如何扩展该 ...

  6. 《ASP.NET Core In Action》读书笔记系列二 ASP.NET Core 能用于什么样的应用,什么时候选择ASP.NET Core

    ASP.NET Core 能用于什么样的应用 ASP.NET Core 可以用作传统的web服务.RESTful服务.远程过程调用(RPC)服务.微服务,这归功于它的跨平台支持和轻量级设计.如下图所示 ...

  7. 《ASP.NET Core In Action》读书笔记系列一 ASP.NET Core 的诞生

    最近打算系统学习一下asp.net  core ,苦于没有好的中文书藉,只好找来一本英文的 <ASP.NET Core In Action>学习.我和多数人一样,学习英文会明显慢于中文.希 ...

  8. StreamSets学习系列之StreamSets的Core Tarball方式安装(图文详解)

    不多说,直接上干货! 前期博客 StreamSets学习系列之StreamSets支持多种安装方式[Core Tarball.Cloudera Parcel .Full Tarball .Full R ...

  9. 《ASP.NET Core 高性能系列》关于.NET Core的配置信息的若干事项

    1.配置文件的相关闲话 Core自身对于配置文件不是必须品,但由上文分析可知ASP.NET Core默认采用appsettings.json作为配置文件,关于配置信息的优先等级 命令行>环境变量 ...

随机推荐

  1. Java学习笔记day_01

    Java学习笔记(复习整理) 虽然不知道该怎么写,但是不起步就永远不知道该怎么做..刚开始可能会写的很差劲,但会一点一点变好的. 本笔记是以我按照传智播客的视频和Java核心思想来学习,前面的基础部分 ...

  2. APP动态加载轮播图片

    如果APP里面的轮播图片是动态加载的话,那么你会发现他不会轮播(前提是mui框架),这里都是用的mui框架,动态加载的图片因为mui的js查不到html上面没有图片,所以就不会轮播,需要手动重置下轮播 ...

  3. oracle存储过程 out cursor

    create or replace procedure BUILDEMPLID(emp_cursor out sys_refcursor) is n_emplid number; n_emplid1 ...

  4. HTML的Tomcat

    修改D:\software\apache-tomcat-8.0.44\webapps\ROOT\WEB-INF\web.xml: <?xml version="1.0" en ...

  5. centos7安装配置nfs

    操作系统版本:3.10.0-123.el7.x86_64 192.168.137.11  nfs服务端 192.168.137.10  nfs客户端 一.安装nfs服务端(在192.168.137.1 ...

  6. java策略设计模式

    1.概述 策略模式定义了一系列的算法,并将每一个算法封装起来,而且使他们可以相互替换,让算法独立于使用它的客户而独立变化. 其实不要被晦涩难懂的定义所迷惑,策略设计模式实际上就是定义一个接口,只要实现 ...

  7. 解决jenkins shell执行sonar-scanner提示命令存在的问题

    通过jenkins的以下三个方式去执行sonar-scanner,抛如下错误. Send files or execute commands over SSH before the build sta ...

  8. [swarthmore cs75] Compiler 6 – Garbage Snake

    课程回顾 Swarthmore学院16年开的编译系统课,总共10次大作业.本随笔记录了相关的课堂笔记以及第9次大作业. 赋值的副作用:循环元组 下面的代码展示了Python3是如何处理循环列表(pri ...

  9. 简单的JavaScript图像延迟加载库Echo.js

    插件描述:和 Lazy Load 一样,Echo.js 也是一个用于图像延迟加载 JavaScript.不同的是 Lazy Load 是基于 jQuery 的插件,而 Echo.js 不依赖于 jQu ...

  10. 第4周小组作业:WordCount优化

     Github项目地址:https://github.com/chaseMengdi/wcPro stage1:代码编写+单元测试 PSP表格 PSP2.1 PSP阶段 预估耗时(分钟) 实际耗时(分 ...