Asp.Net Core 缓存的使用(译)

摘要:
1.如前所述,在Startup类中启用缓存功能;}AddMemoryCache()方法将内存缓存函数添加到服务集合;PublicHomeController(IMemoryCachecache){this.cache=cache;}…}通过构造函数注入缓存对象;()方法将记录添加到缓存;4.添加缓存后,使用Get()方法获取缓存。}上面的代码演示了从缓存中获取数据;

原文:http://www.binaryintellect.net/articles/a7d9edfd-1f86-45f8-a668-64cc86d8e248.aspx
环境:Visual Studio 2017, Asp.Net Core 1.1.

缓存机制主要是为了提高性能。在ASP.NET Web Forms 及 ASP.NET MVC中可以直接使用缓存对象(Caching object)缓存数据。这通常被称作“服务器端缓存”,是 Framework 的内置特性。虽然Asp.Net Core没有这样的缓存对象,但依然可以轻松的实现缓存功能。本文将对此进行介绍。

继续阅读之前,请先使用 Web Application 项目模板创建一个 Asp.net Core 的应用程序:

Asp.Net Core 缓存的使用(译)第1张

注:使用缓存功能,需通过NuGet安装“Microsoft.Extensions.Caching.Memory”扩展包。使用时引用:using Microsoft.Extensions.Caching.Memory;
1. 在Startup类中开启缓存功能

如前所述,Asp.Net Core 没有内建的缓存对象,因此不能在 Controller 中使用它们。在Asp.Net Core中要使用内存缓存,需要在 Startup 类中依赖注入(DI)内存缓存服务(in-memory caching service)。打开Startup 文件,修改 ConfigureServices() 方法如下:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services.AddMemoryCache();
}

 AddMemoryCache() 方法将内存缓存功能加入到服务集合中。

2. 控制器中注入缓存对象

修改HomeController如下:

public class HomeController : Controller
{
    private IMemoryCache cache;

    public HomeController(IMemoryCache cache)
    {
        this.cache = cache;
    }
    ...
}

通过构造函数注入缓存对象,我们在控制器中就有了可用的缓存变量。

3. 使用Set()方法缓存一个对象

 有了IMemoryCache 对象,你就可以非常方便读取或写入缓存数据。

public IActionResult Index()
{
    cache.Set<string>("timestamp", DateTime.Now.ToString());
    return View();
}

上面代码使用 IMemoryCache 的 Set<T>() 方法将一条记录加入到了缓存中。Set() 方法第一个参数为缓存名称,第二个参数为其值。

4. 使用Get()方法获取缓存

 一旦您添加了缓存,就可以通过 Get() 方法来获取它们。

public IActionResult Show()
{
    string timestamp = cache.Get<string>("timestamp");
    return View("Show", timestamp);
}

上面代码演示了从缓存中获得数据,Get() 方法指定了缓存名和返回数据类型。

下面用于显示获得的缓存:

<h1>TimeStamp : @Model</h1>
<h2>@Html.ActionLink("Go back", "Index", "Home")</h2>

运行你的应用程序,打开 /Home/Index ,此时将生成了一个时间戳并存入缓存中。然后打开 /Home/Show 观察是否已从缓存中获得了时间戳数据。/Home/Show 页面会显示如下:

Asp.Net Core 缓存的使用(译)第2张

5. 使用TryGet()方法检查是否存在指定缓存项

上面示列中,每次访问 /Home/Index 都将生成一个新的时间戳并进行缓存,这是因为没有检查是否已存在同名的缓存项。有两种方式检测同名缓存项:

//first way
if (string.IsNullOrEmpty(cache.Get<string>("timestamp")))
{
    cache.Set<string>("timestamp", DateTime.Now.ToString());
}

//second way
if (!cache.TryGetValue<string>("timestamp", out string timestamp))
{
    cache.Set<string>("timestamp", DateTime.Now.ToString());
}

第一种方法仍然使用Get()方法,如未能获取到值,则返回 IsNullOrEmpty()。

第二种方法更加优雅一些,使用TryGet()方法获取值。TryGet()方法返回一个布尔值来表示缓存项是否存在,实际的缓存值将通过 out 参数获得。

6. 使用GetOrCreate()添加不存在的缓存项

你可能有这样的需求,缓存项如果存在则取出,如果不存在则创建。此时可以使用 GetOrCreate() 方法:

public IActionResult Show()
{
    string timestamp = cache.GetOrCreate<string>("timestamp", entry => {
        return DateTime.Now.ToString();
    });
    return View("Show", timestamp);
}

使用GetOrCreate() 方法检查timestamp是否存在,如果存在则直接赋值给本地变量,反之则创建一个新的缓存项。

现在直接访问/Home/Show页面,可以看到timestamp已显示。timestamp并没有通过/Home/Index赋值。

7. 设置缓存的决绝和滑动(sliding)期限

在之前的示列中,缓存数据会一直存在,直到调用Remove()方法。你也可以为缓存设置绝对期限和滑动期限。绝对期限就是为缓存设置一个明确的过期时间,滑动期限就是空闲多少时间之后移除缓存。

你可以通过 MemoryCacheEntryOptions对象设置缓存期限策略:

public IActionResult Index()
{
    //cache.Set<string>("timestamp", DateTime.Now.ToString());

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

    return View();
}

上面代码在Index() action中创建了MemoryCacheEntryOptions对象,并同时设置了一个绝对期限为1分钟与滑动期限为1分钟的策略。MemoryCacheEntryOptions对象作为Set()方法的第三个参数传递。

8. 定义移除缓存之后的回调函数

有时候你可能需要在缓存移除后获得通知。缓存被移除有以下2种原因,一是调用了Remove()方法,二是到期后自动移除。你可以通过设定回调函数获得移除缓存之后的通知:

public IActionResult Index()
{
    //cache.Set<string>("timestamp", DateTime.Now.ToString());

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

    return View();
} 

上面代码示例了通过RegisterPostEvictionCallback方法设定回调函数,在本例中回调函数名为MyCallback,第二个参数是你希望传递给回调函数的状态参数,本例我们将HomeController实例作为状态参数传递给回调函数。

回调函数方法如下:

private static void MyCallback(object key, object value, EvictionReason reason, object state)
{
    var message = $"Cache entry was removed : {reason}";
    ((HomeController)state).cache.Set("callbackMessage", message);
}

看看上面代码,MyCallback() 是一个在HomeController中的私有静态函数,有四个参数。前两个参数是被移除的缓存数据所对应的键/值,第三个参数表示移除的原因。EvictionReason是一个枚举类型,可能原因有过期、移除和替换。

在函数体中,我们仅定义了一个string类型的message表示移除原因。如果我们想要把这个message作为另一个缓存项,就需要访问HomeController的缓存对象,此时就要使用第四个参数state。使用state对象获得HomeController中的缓存,同时使用Set()方法设置了一个名为“callbackMessage”的缓存项。

callbackMessage可以在Show() action中获得:

public IActionResult Show()
{
    string timestamp = cache.Get<string>("timestamp");
    ViewData["callbackMessage"] = cache.Get<string>("callbackMessage");
    return View("Show", timestamp);
}

在Show页面呈现:

<h1>TimeStamp : @Model</h1>
<h3>@ViewData["callbackMessage"]</h3>
<h2>@Html.ActionLink("Go back", "Index", "Home")</h2>

测试回调方法,运行程序并访问/Home/Index页面,然后再访问/Home/Show页面,不断刷新Show页面直到缓存过期,页面会显示过期原因。

Asp.Net Core 缓存的使用(译)第3张

9. 缓存的优先级

和过期策略一样,缓存优先级同样使用MemoryCacheEntryOptions:

MemoryCacheEntryOptions options = new MemoryCacheEntryOptions();
options.Priority = CacheItemPriority.Normal;
cache.Set<string>("timestamp", DateTime.Now.ToString(), options);

CacheItemPriority枚举值有普通,高和永久保留。

10. 设置缓存之间的依赖关系

可以为缓存数据设置依赖关系,实现删除一个缓存项后,其依赖的缓存项同时被移除的功能。请按如下代码更新Index() action:

public IActionResult Index()
{
    var cts = new CancellationTokenSource();
    cache.Set("cts", cts);

    MemoryCacheEntryOptions options = new MemoryCacheEntryOptions();
    options.AddExpirationToken(new CancellationChangeToken(cts.Token));
    options.RegisterPostEvictionCallback(MyCallback, this);
    cache.Set<string>("timestamp",DateTime.Now.ToString(), options);

    cache.Set<string>("key1", "Hello World!",new CancellationChangeToken(cts.Token));
    cache.Set<string>("key2", "Hello Universe!",new CancellationChangeToken(cts.Token));

    return View();
}
注:通过NuGet安装“Microsoft.Extensions.Primitives”程序包,同时添加对System.Threading的引用。

上面代码首先创建了一个CancellationTokenSource对象,并将其设置成名为“cts”的缓存项。然后创建MemoryCacheEntryOptions对象,并使用AddExpirationToken()方法指定一个特殊的过期令牌(expiration token),这里我们暂不深究CancellationChangeToken。

expiration token允许你“过期”一个缓存项,如果令牌是“active”状态则保留缓存项,如果是“cancelled”则从缓存中移除。一旦缓存项被移除则调用MyCallback方法。代码接着创建了两个缓存项 key1和key2,创建时第三参数传递了一个使用cts对象初始化的CancellationChangeToken。

现在我们有了三个缓存项,timestamp是主缓存项,key1和key2依赖与timestamp。当timestamp被移除时,会同时移除key1和key2。移除timestamp需要取消它的令牌。

public IActionResult Remove()
{
    CancellationTokenSource cts = cache.Get<CancellationTokenSource>("cts");
    cts.Cancel();
    return RedirectToAction("Show");
}

我们从缓存中获得先前定义的CancellationTokenSource对象同时执行Cancel()方法,timestamp移除的同时key1与key2也一并移除了。

测试一下上面代码,运行程序并访问/Home/Index页面,再访问/Home/Show页面,同时检查三个缓存项是否按预期显示。然后访问/Home/Remove,你将重新被导航到/Home/Show页面。当Remove() action被调用时,令牌被标记为取消,所有的值将被移除。Show页面将显示过期原因为“令牌过期”:

Asp.Net Core 缓存的使用(译)第4张

免责声明:文章转载自《Asp.Net Core 缓存的使用(译)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Emoji表情符号兼容方案UISwitch开关下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

(二)Java数组特性总结,你真的了解数组吗?

一、数组的特殊性 (一)数组标识符是一个引用,指向堆中创建的一个真实对象,这个对象(数组)保存了指向保存其他对象的引用。 (二)数组中保存引用类型时保存的是对象引用,基本数据类型数组保存基本数据的值。 (三)数组的length只表示数组能够容纳多少元素,不能保存实际保存的元素个数。 (四)多维数组可以使用Arrays.deepToString()将多维数组...

使用boost线程定时器作为后台线程来切换主循环程序状态方法总结

  1:简单了解boost定时器 #include "stdafx.h" #include <string> #include <boost hread.hpp> #include <boost/asio.hpp> #include <iostream> using namespace boost::asi...

Linux cached过高问题

1. cached主要负责缓存文件使用,日志文件过大造成cached区内存增大把内存占用完. Free中的buffer和cache:(它们都是占用内存):buffer : 作为buffer cache的内存,是块设备的读写缓冲区cache: 作为page cache的内存, 文件系统的cache如果 cache 的值很大,说明cache住的文件数很多。 L...

【进制转换】原码反码和补码的理解以及进制转换

一、编码理解: 1、原码: 正数:按照绝对值大小转换成的二进制数; 负数:按照绝对值大小转换成的二进制数,然后最高位补1,称为原码。 00000000 00000000 00000000 00000101 是 5的 原码; 10000000 00000000 00000000 00000101 是 -5的 原码。 2、反码: 正数:与原码相同; 负...

java内存泄露与内存溢出

java内存泄露与内存溢出 基本概念 内存泄露:指程序中动态分配内存给一些临时对象,但是对象不会被GC所回收,它始终占用内存。即被分配的对象可达但已无用。 内存溢出:指程序运行过程中无法申请到足够的内存而导致的一种错误。内存溢出通常发生于OLD段或Perm段垃圾回收后,仍然无内存空间容纳新的Java对象的情况。 从定义上看,内存泄露是内存溢出的一种诱因,不...

Swing中怎样使JScrollPane中滚动条始终在最下面

最近用swing写了一个简单的聊天界面,但是页面上的JScrollPane一直移动在最上面,下面是解决怎么让JScrollPane移动到最后一行的几种方法: 1. 利用JTextArea的selectAll();方法在添加信息之后强制将光标移动到最后一行。据说是Aviva中采用的方式。 2.使用JTextArea的setCaretPosition();手动...