关于 ASP.NET 内存缓存你需要知道的 10 点

缓存机制的主要目的是提高应用程序的性能。作为 ASP.NET 开发人员,你可能会意识到 ASP.NET Web 窗体以及 ASP.NET MVC 可以使用 Cache 对象缓存应用程序的数据。这通常被称为服务器端数据缓存,并且常作为框架的内置功能。虽然 ASP.NET Core 中并没有这样的 Cache 对象,但是你可以很容易地实现内存缓存。本文将向你说明如何实现。

在进一步阅读之前,你先创建一个基于 Web 应用程序项目模板的新的 ASP.NET Core 应用程序。

4418040-1c0a4af35d7042d1

然后按照下面提到的步骤逐一构建和测试由内存缓存提供的各种功能。

1. 内存缓存需要在启动类 Startup 中启用一下

不同于 ASP.NET Web 窗体和 ASP.NET MVC,ASP.NET Core 没有内置的 Cache 对象,可以拿来在控制器里面直接使用。 这里,内存缓存时通过依赖注入来启用的,因此第一步就是在 Startup 类中注册内存缓存的服务。如此,就得打开 Startup 类然后定位到 ConfigureServices() 方法,像下面这样修改 ConfigureServices() 方法:

publicvoidConfigureServices(IServiceCollection services){    services.AddMvc();        services.AddMemoryCache();}

为了向你的应用程序加入内存缓存能力,你需要在服务集合上调用 AddMemoryCache() 方法。采用这种办法就可以让一个内存缓存(它是一个 IMemoryCache 对象)的默认实现可以被注入到控制器中去。

2. 内存缓存使用依赖注入来注入缓存对象

然后打开 HomeController 并对其进行修改,如下所示:

publicclassHomeController:Controller{privateIMemoryCache cache;publicHomeController(IMemoryCache cache){this.cache = cache;    }    ....}

如你所见,上述代码声明了一个 ImemoryCache 的私有变量。该变量会被构造器中被赋值。构造器会通过 DI(依赖注入)接收到缓存参数,然后被存储在本地变量总,提供后续使用。

3. 你可以使用 Set() 方法来在缓存中存东西

等你有了这个 IMemoryCache 对象,就可以读取或者向它写入数据了。向缓存写入数据项是相当直接的。

publicIActionResultIndex(){  cache.Set("timestamp", DateTime.Now.ToString());returnView();}

上述代码在 Index() 这个 action 中设置了一个缓存项。这是通过使用 IMemoryCache 的 Set() 来完成的。Set() 方法的第一个参数是键名,用来标识该数据项。第二个参数是键的取值。在此例中,我们存储一个字符串的键和一个字符串的值,而你也可以存储其它类型 (原生以及自定义的类型) 的键值对。

4. 你可以使用 Get 方法来从缓存中获取到一个数据项

等你向缓存中添加好了数据,也许会想要在应用程序的其它地方去获取到该数据,可以用 Get() 来做到。如下代码会告诉你如何来做这件事情。

public IActionResultShow(){stringtimestamp= cache.Get("timestamp");  return View("Show",timestamp);

}

上述代码从 HomeController 的另外一个action(Show)那里获取到了一个缓存的数据项。Get() 方法会指定数据项的类型以及它的键名。如果该数据项存在的话,就会被返回并且被赋值给 timestamp 这个字符串变量。然后这个 timestamp 的值就会被传递给 Show 视图。

Show 视图只是简单地输出了 timestamp 的值,如下所示:

TimeStamp : @Model

@Html.ActionLink("Go back","Index","Home")

为了对目前为止你所写的代码进行一下测试,请运行应用程序。首先将浏览器导航至 /Home/Index ,这样 timestamp 键就会被赋值。然后导航至 /Home/Show 并查看 timestamp 值是否会输出。下图所示是 Show() 这个 action 运行起来的一个例子。

4418040-c5506b503ae2b18f.gif

5. 你可以使用 TryGet() 来检查缓存中是否存在特定的键值

如果你观察前面的示例,会发现每次你导航至 /Home/Index 的时候, 都会有一个新的 timestamp 被赋值给了缓存项。这是因为我们并没有对此进行检查,规定只有在数据项不存在的时候才赋值。许多时候你都会想要这样做的。这里有两种办法可以在 Index() 这个 action 里面来做这样的检查。我们把两种办法都在下面列了出来。

//first wayif(string.IsNullOrEmpty(cache.Get("timestamp"))){  cache.Set("timestamp", DateTime.Now.ToString());}//second wayif(!cache.TryGetValue("timestamp",outstringtimestamp)){    cache.Set("timestamp", DateTime.Now.ToString());}

第一种办法使用了你早先用过的同一个 Get() 方法,这一次它被拿来跟 if 块一起用。如果 Get() 不能在缓存中找到指定的数据项,IsNullOrEmpty() 就会返回 true。而只有这时候 Set() 才会被调用,一次来添加数据项。

第二种办法更加优雅一点。它使用 TryGet() 方法来获取一个数据项。TryGet() 方法会返回一个布尔值来指明数据项有没有被找到。实际的数据项可以使用一个输出参数拉取出来。如果 TryGet() 返回false,Set() 就会被用来添加数据。

6. 如果不存在的话,可以使用 GetOrCreate() 来添加一项

有时你需要从缓存中检索现有项。如果该项目不存在,则希望添加该项。这两个任务 - 如果它存在获取值,否则创建之 - 可以使用 GetOrCreate() 方法来实现。修改后的 Show() 方法展示了如何实现的。

publicIActionResultShow(){stringtimestamp = cache.GetOrCreate  ("timestamp", entry => {returnDateTime.Now.ToString(); });returnView("Show",timestamp);}

Show() 动作现在使用 GetOrCreate() 方法。 GetOrCreate() 方法将检查时间戳的键值是否存在。如果是,现有值将被赋值给局部变量。否则,将根据第二个参数中指定的逻辑创建一个新条目并将其添加到缓存中。

为了测试此代码,请直接运行 /Home/Show,不需要跳转到 /Home/Index。你仍然会看到输出的时间戳值,因为在该值不存在的情况下,GetOrCreate() 现在是添加了它。

7. 你可以在一个缓存的数据项上面设置绝对和滚动的过期时间

在前述示例中,一个缓存项只要被添加到缓存就会一直存储,除非它被明确地使用 Remove() 从缓存中移除。你也可以在一个缓存项上面设置一个绝对和滚动的过期时间。一个绝对的过期设置意味着该缓存项会在严格指定的日期和时间点被移除,而滚动过期设置则意味着它在给定的一段时间量处于空闲状态(也就是没人去访问)之后被移除。

为了能在一个缓存项上面设置这两种过期策略,你要用到 MemoryCacheEntryOptions 对象。如下代码向你展示了如何去使用。

MemoryCacheEntryOptions options =newMemoryCacheEntryOptions();options.AbsoluteExpiration = DateTime.Now.AddMinutes(1);options.SlidingExpiration = TimeSpan.FromMinutes(1);cache.Set("timestamp", DateTime.Now.ToString(), options);

上述代码来自于修改过的 Index() action,它创建了一个 MemoryCacheEntryOptions 的对象,然后将它的 AbsoluteExpiration 属性设置为从此刻到一分钟之后的一个 DateTime 值,它还将 SlidingExpiration 属性设置为一分钟。这些值都指定了该缓存项会在一分钟之后从缓存移除,不管其是否会被访问。此外,如果该缓存项如初持续空闲了有一分钟,它也会被从缓存中移除。

等你将 AbsoluteExpiration 和 SlidingExpiration 的值设置后, Set() 方法就可以被用来将一个数据项添加到缓存。这一次 MemoryCacheEntryOptions 对象会被作为第三个参数传递给 Set() 方法。

8. 当缓存项会被移除时,你可以连接回调

有时你会想要在缓存项从缓存中被移除时收到通知。可能会有多种原因需要从缓存中移除数据项。例如,因为明确地执行了 Remove() 方法而移除了一个缓存项, 也有可能是因为它的 AbsoluteExpiration 和 SlidingExpiration 值已经到期而被移除,诸如此类的原因。

为了能知道项目是何时从缓存移除的,你需要编写一个缓存函数。如下代码向你展示了如何去做这件事情:

MemoryCacheEntryOptions options =newMemoryCacheEntryOptions();options.AbsoluteExpiration = DateTime.Now.AddMinutes(1);options.SlidingExpiration = TimeSpan.FromMinutes(1);options.RegisterPostEvictionCallback(MyCallback,this);cache.Set("timestamp", DateTime.Now.ToString(), options);

上述代码同之前使用 MemoryCacheEntryOptions 来配置 AbsoluteExpiration 和 SlidingExpiration 的代码相当类似。更加重要的是它也调用了 RegisterPostEvictionCallback() 方法来绑定刚刚讨论过的回调函数。在这里回调函数被命名为 MyCallback。第二个参数是一个你会想要传递给回调函数的状态对象。这里我们传入了 HomeController 的实例 (用 this 将当前的 HomeController 对象“点”出来) 作为状态对象。

前面提到的MyCallback函数,其代码如下所示:

privatestaticvoidMyCallback(objectkey,objectvalue,EvictionReason reason,objectstate){varmessage = $"Cache entry was removed : {reason}";    ((HomeController)state).cache.Set("callbackMessage", message);}

请仔细观察这段代码。 MyCallback() 是 HomeController 类里面的一个私有静态函数,它有四个参数。前面两个参数表示刚刚删除的缓存项的键和值,第三个参数表示的是该数据项被删除的原因。EvictionReason 是一个枚举类型,它维护者各种可能的删除原因,如过期,删除以及替换。

在回调函数的内部,我们会基于删除的原因构造一个字符串消息。我们想要将此消息设置成另外一个缓存项。这样做的话就需要访问 HomeController 的缓存对象,此时状态参数就可以排上用场了。使用状态对象,你可以对 HomeController 的缓存对象进行控制,并使用 Set() 增加一个 callbackMessage 缓存项。

你可以通过 Show() 这个 action 来访问到 callbackMessage,如下所示:

public IActionResultShow(){stringtimestamp= cache.Get("timestamp");  ViewData["callbackMessage"] =    cache.Get("callbackMessage");  return View("Show",timestamp);

}

最后就可以在 Show 视图中显示出来了:

TimeStamp : @Model

@ViewData["callbackMessage"]

@Html.ActionLink("Go back","Index","Home")

欢迎关注我的公众号(同步更新文章)DoNet技术分享平台

阅读原文

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/272640.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux git删除的文件怎么还原,从Git仓库中恢复已删除的分支、文件或丢失的commit...

从Git仓库中恢复已删除的分支、文件或丢失的commit在使用Git的过程中,有时可能会有一些误操作比如:执行checkout -f 或 reset -hard 或 branch -d删除一个分支结果造成本地(远程)的分支或某些commit丢失可以通过reflog来进行恢复,前提是丢失的…

两张趣图助你理解状态码的含义~

HTTP状态码(HTTP Status Code)是用以表示网页服务器HTTP响应状态的3位数字代码。我们可以通过查看HTTP状态码来判断服务器状态,常见的有404 、502等;但是其他不是很常见的状态码都代表什么状态呢?下面有两张有趣的图片…

java 自定义注解以及获得注解的值

1.自定义注解 import java.lang.annotation.*;Documented Target(ElementType.FIELD) Inherited Retention(RetentionPolicy.RUNTIME ) public interface MyAnno {/*** 是否能为null* return*/boolean isCanNull() default true;/*** 是否能为空字符串* return*/boolean isCanE…

linux列出管道,lsof列出的管道列表示什么意思?_linux_开发99编程知识库

文件不僅以流形式打開。 其中一些是在 lsof 手冊中列出的:FD is the File Descriptor number of the file or:cwd current working directory;Lnn library references (AIX);err FD information error (see NAME column);jld jail directory (FreeBSD);ltx shared l…

CSS一些实用的技巧

css 字体简写规则当使用css定义字体时你可能会这样做:font-size: 1em;line-height: 1.5em;font-weight: bold;font-style: italic;font-variant: small-caps;font-family: verdana,serif;事实上你可以简写这些属性:font: 1em/1.5em bold italic small-ca…

linux openssh升级8.1,Centos7利用rpm升级OpenSSH到openssh-8.1p1版本

由于近期安全事故频发,打算把机器OpenSSH升级到最新版本,找了一圈,发现分享的rpm包就到7.4版本,最新版已经到8.1.p1,所以博客自编译一个openssh-8.1p1的rpm包进行分享。检查环境:[roottest]# ssh -VOpenSSH…

《HTTP权威指南》 – 11.验证码和新鲜度

服务器应当告知客户端能够将内容缓存多长时间,在这个时间内就是新鲜的。服务器可以用这两个首部之一来提供信息: Expires(过期)Cache - Control(缓存控制)Expires首部 规定文档“过期”的具体时间&#xff…

产品经理必备神器推荐

欢迎关注我的公众号(同步更新文章):DoNet技术分享平台阅读原文工欲善其事,必先利其器,作为最追求极致体验的产品经理群体,手里有一件趁手的法器,工作起来才会有一种享受般的快感,最近…

野火linux底板设计,野火STM32F767套件(底板+核心板)

一、兑换形式1、电子芯吧客注册用户均可通过免费申请与硬件兑换两种方式进行申请试用2、免费申请形式为用户通过分享试用活动至好友,换取申请板卡一次试用资格3、硬件兑换方式为用户捐赠一块闲置板卡至电子芯吧客,换取申请板卡一次试用资格4、免费申请渠…

c++ builder xe2 (Embarcadero rad studio) 远程调试 同样适用于 delphi 远程调试 教程

c builder xe2 (Embarcadero rad studio) 远程调试 同样适用于 delphi 远程调试 教程转载于:https://www.cnblogs.com/LittleTiger/p/5039245.html

JS关闭浏览器 (不弹出提示框)

如果网页不是通过脚本程序打开的(window.open()),调用window.close()脚本关闭窗口前,必须先将window.opener对象置为null,否则浏览器(IE7、IE8)会弹出一个确定关闭的对话框。<script…

天大18年c语言离线作业,天大18秋C语言程序设计在线作业一辅导资料.docx-资源下载在线文库www.lddoc.cn...

天大18秋《C语言程序设计》在线作业一辅导资料.docx天大 18 秋C 语言程序设计 在线作业一1、C 2、D 3、D 4、D 5、D 一、单选题共 40 题,100 分1、设有int a 31,0,3,3,4,5,6,7;,则 a21的值是 A3B5C6D4正确答案是C2、设 int a21,b021; 语句 printf“x,dn”,a,b;的输出…

AM335x(TQ335x)学习笔记——GPIO关键驱动移植

或按照S5PV210学习秩序。我们首先解决的关键问题。TQ335x有六个用户按钮,每个上、下、剩下、对、Enter和ESC。我想开始学习S5PV210当同一,写输入子系统驱动器的关键问题要解决,但浏览driver/input/keyboardgpio-keys.c,大体上看下…

程序员偷偷深爱的9个不良编程习惯

新媒体管家下面这9个编码习惯,虽然在编程规则中是被驳斥的,但我们很多人就是会不由自主地使用它们。我们曾经都做过这样的事情:当妈妈不注意的时候,偷偷地吃糖果零食,然后导致有了蛀牙。同样的,我们都违背过…

emacs c语言 自动补全,Emacs 与 C/C++ 代码自动补全

基于 Emacs 的 company 模式并配合 semantic 文法分析器,实现 Emacs 的 C/C 代码自动补全。关于 Emacs 的代码自动补全代码自动补全的功能,对于使用 Emacs 写代码的程序员而言其重要性不言而喻的,但是搜了一些所谓的 “Emacs 完美的 C 自动补…

linux(fedora) 下dvwa 建筑环境

linux(fedora)下dvwa组态 1.下载httpd,dvwa,mysql,mysqlserver, php-mysql,php 除了dvwa 这是外界进入下一官方网站。该服务通过休息install 安装 yum install httpd, mysql, php-mysql, php 假设出现安装的问题。能够先yum search xxx 2.安装完之后,检查安装的状…

c语言一元二次方程 ii(分支嵌套),C程序设计——求一元二次方程算法

要求:从键盘上输入一元二次方程的三个参数,编程判断并求一元二次方程的实根(a,b,c均为整数)算法分析:一元二次方程是只含有一个未知数,且未知数的最高次数是二次的多项式方程。一元二次方程经过整理都可化成一般形式axbxc0(a≠0)&…

程序员如何优雅度过一生的15个建议

首先,我要说明一下精彩的职业生涯应该是什么样。他们不是这样的一个线性图形,不是每过一个月你就会有对应的成长。(就算是普通的职业生涯也不会这样。你不会每个月都有提升。每个月你都会变的好一点,但是每次有提升都是大幅度的&a…

cocos2d-x游戏开发 跑酷(四) 关联与物理世界

原创。转载注明出处http://blog.csdn.net/dawn_moon/article/details/21451077 前面一节尽管实现了一个跑动的人物,可是他只不过一个精灵在运行一个跑动的帧动画而已。这一节我要实现精灵和物理世界关联。让这个人跟实际的Parkour一样,有实际体积&#x…

kmp算法的c语言,KMP算法 纯C实现

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼我自己写的KMP算法:int nt[256];void get_next1(char* T, int next[], int tlen){int i 0;int j 1;next[0] -1;while( j {if ( T[i] T[j] ){next[j] 0;i;}else{next[j] i;i 0;}j;}}int Index_KMP1(char* S, cha…