作者:暴王

个人博客: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. squid代理加用户认证

    squid代理加用户认证 用authentication helpers添加身份验证 有如下几种认证方式 :=> NCSA: Uses an NCSA-style username and pa ...

  2. du

    du -ah --max-depth=1     这个是我想要的结果  a表示显示目录下所有的文件和文件夹(不含子目录),h表示以人类能看懂的方式,max-depth表示目录的深度.

  3. 关于阿里云ECS服务器修改远程端口的一点总结

    般修改公司的远程服务器的登录端口号分为两大步: 一.修改注册表中的两个地方的端口号:(注册表打开命令:regedit) [HKEY_LOCAL_MACHINE\SYSTEM\CurrentContro ...

  4. bootstrap-table使用详解

    尴尬,标记果然到了一周之后.... 首先引入文件不必提,引入bootstrap和bootstrap-table <link rel="stylesheet" href=&qu ...

  5. ASP.NET获取POST提交过来的数据流,转换成Json格式的字符串

    public class Public { private static Public _instance = new Public(); /// <summary> /// 全局访问点 ...

  6. pdo的简单介绍和使用

    1,PDO的定义:php data object(php数据对象); 2,连接pdo的相关参数:$dsn.$user.$pass. 其中$dsn="mysql:host=$host;dbna ...

  7. weka环境配置

    java环境变量设置: 安装jdk到具体目录"ABC"下当前目录下应该有jdk+版本号和jre加版本号. 然后打开环境变量:新建JAVA_HOME内容是:jdk的安装目录.例如:D ...

  8. [转]kaldi基于GMM做分类问题

    转自:http://blog.csdn.net/zjm750617105/article/details/55211992 对于每个类别的GMM有几种思路: 第一是将所有训练数据按类别分开,每类的数据 ...

  9. 工作jQuery基础复习(一)

    1.prop() 方法 设置或者返回被选元素的属性和值 当该方法用于返回属性值时,则返回第一个匹配元素的值 当该方法设定属性值时,则为匹配元素集合设置一个或者多个属性/值对

  10. 一文读懂高性能网络编程中的I/O模型

    1.前言 随着互联网的发展,面对海量用户高并发业务,传统的阻塞式的服务端架构模式已经无能为力.本文(和下篇<高性能网络编程(六):一文读懂高性能网络编程中的线程模型>)旨在为大家提供有用的 ...