这两天在看.net core的in memory cache,这里记录一下用法,主要涉及MemoryCache的Get/Set/Expire/Flush。
首先我们先用dotnet命令创建一个mvc的项目,这里我们将使用postman来请求server,

1
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作为参数,如果找到则返回找到的值,若找不到则返回空
现在我们可以在命令行里输入

1
2
dotnet restore
dotnet run

来启动web项目,之后我们可以通过

1
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缓存了,地址是:

1
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里根据需要判断缓存是因为什么原因被移除,才能避免意外的回调触发。

原文地址: https://www.cnblogs.com/xiandnc/p/9517017.html


.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com

C#系列之聊聊.Net Core的InMemoryCache相关推荐

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

    <ASP.NET Core In Action>读书笔记系列五 ASP.NET Core 解决方案结构解析1 参考文章: (1)<ASP.NET Core In Action> ...

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

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

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

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

  4. .NET平台系列22:.NET Core/.NET5/.NET6 对比 .NET Framework

    系列目录     [已更新最新开发文章,点击查看详细] 在我的博客<.NET平台系列2 .NET Framework 框架详解>与 <.NET平台系列7 .NET Core 体系结构 ...

  5. 精通Server Core系列之二 ---Server Core安装与基本配置

    Server Core安装其实很简单,同前面的Windows Server 2008安装步骤一样,只要在选择安装操作系统这里,选择Server Core安装即可,这里使用Enterprise版本的服务 ...

  6. 【asp.net core 系列】14 .net core 中的IOC

    0.前言 通过前面几篇,我们了解到了如何实现项目的基本架构:数据源.路由设置.加密以及身份验证.那么在实现的时候,我们还会遇到这样的一个问题:当我们业务类和数据源越来越多的时候,我们无法通过普通的构造 ...

  7. Entity Framework Core系列教程-25-Entity Framework Core日志

    Entity Framework Core日志 我们经常需要在EF Core中记录SQL并更改跟踪信息以进行调试. EF Core日志记录自动与.NET Core的日志记录机制集成.因此,在隐含使用E ...

  8. 【机器学习系列】聊聊决策树

    决策树是简单易学且具有良好解释性的模型,但实话说,我在工作中用的不多,通常会选择更加复杂一些的模型,如随机森林.XGBoots之类的模型,但要理解这些模型,对决策树的学习是必不可少的,所以本文就基于s ...

  9. C++ 不知算法系列之聊聊希尔、归并排序算法中的分治哲学

    1. 前言 排序算法中,冒泡.插入.选择属于相类似的排序算法,这类算法的共同点:通过不停地比较,再使用交换逻辑重新确定数据的位置. 希尔.归并.快速排序算法也可归为同一类,它们的共同点都是建立在分治思 ...

最新文章

  1. log4j打印mybatis执行的sql
  2. 新浪php面试题目,新浪php的面试题 收集
  3. swift_043(Swift 懒加载(lazy) )
  4. 【HDU 4547 CD操作】LCA问题 Tarjan算法
  5. python 3.6.5编译安装_Centos7下编译安装python3.6.5
  6. JS Event事件
  7. SpringMVC的请求-获得请求参数-获得POJO类型参数
  8. python各个版本改动
  9. mysql 多行 连续_mysql多表连续查询的问题
  10. java 蓝桥杯算法训练 每月的天数(题解)
  11. cad常青藤插件_CAD作图效率低怎么办?最全辅助插件大合集,绘图效率提升70%,限时分享...
  12. HttpClient短信接口
  13. UBNT设置AP模式注意事项
  14. 常用的红色的RGB值
  15. python网站攻击-利用Python进行Web渗透测试(十):密码攻击
  16. 杜一楠的反躬自省与24券的墓志铭
  17. 心灵奇旅最触动我的一段
  18. 英语外刊精读(Part 2):day1,泛读;day2, 精读(上);day3, 精读(下)
  19. 解决 C# GetPixel 和 SetPixel 效率问题
  20. 【实验】虚拟驱动模拟实验

热门文章

  1. Docker 私有仓库的搭建
  2. 《Java线程与并发编程实践》—— 2.3 谨防活跃性问题
  3. VMWare虚拟机NAT上网方法 亲测可用
  4. MetroGridHelper: A helpful debugging assistant for designers and developers alike
  5. error LNK2001: unresolved external symbol public: __thiscall CNaDialog::CNaDialog(class CWnd *)
  6. 用PHP实现POP3邮件的收取(一)
  7. Avalonia-.NET 的跨平台 UI 框架
  8. 技术分享 | 混合云模式下SaaS端前端最佳实践
  9. 客官,.NETCore无代码侵入的模型验证了解下
  10. 池化对象 RecyclableMemoryStream 在 .netcore 中的使用