<li id="2aw4k"></li>
  • <div id="2aw4k"><tr id="2aw4k"></tr></div>
  • <div id="2aw4k"><tr id="2aw4k"></tr></div>
    <center id="2aw4k"><small id="2aw4k"></small></center><center id="2aw4k"><small id="2aw4k"></small></center>
    首页»ASP.NET»关于 ASP.NET Core 内存缓存你需要知道的 10 点

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

    来源:oschina 发布时间:2017-06-23 阅读次数:

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

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

      ?#32531;?#25353;照下面提到的步骤逐?#36824;?#24314;和测试由内存缓存提供的各种功能。

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

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

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

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

     2. 内存缓存使用?#35272;?#27880;入来注入缓存对象

      ?#32531;?#25171;开 HomeController 并?#20113;?#36827;行修?#27169;?#22914;下所示:

    public class HomeController : Controller
    {
        private IMemoryCache cache;
    
        public HomeController(IMemoryCache cache)
        {
            this.cache = cache;
        }
        ....
    }

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

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

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

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

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

     4. 你可以使用 Get 方法?#21019;?#32531;存中获取到一个数据项

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

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

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

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

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

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

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

      如果你观察前面的示例,会发?#32622;?#27425;你导航至 /Home/Index 的时候, 都会有一个新的 timestamp 被赋值给了缓存项。这是因为我们并没有?#28304;?#36827;行检查,规定只有在数据项不存在的时候才赋值。许多时候你都会想要这样做的。这里有两?#32844;?#27861;可以在 Index() 这个 action 里面来做这样的检查。我?#21069;?#20004;?#32844;?#27861;都在下面列了出来。

    //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());
    }

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

      第二?#32844;?#27861;更加优雅一点。它使用 TryGet() 方法来获取一个数据项。TryGet() 方法会返回一个布尔?#36947;?#25351;明数据项有没有被?#19994;健?#23454;际的数据项可以使用一个输出参数拉取出来。如果 TryGet() 返回false,Set() 就会被用来添加数据。

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

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

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

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

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

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

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

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

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

      上述代码来自于修改过的 Index() action,它创建了一个 MemoryCacheEntryOptions 的对象,?#32531;?#23558;它的 AbsoluteExpiration 属性设置为从此刻到一?#31181;?#20043;后的一个 DateTime 值,它还将 SlidingExpiration 属性设置为一?#31181;印?#36825;些值都指定了该缓存项会在一?#31181;?#20043;后从缓存移除,?#36824;?#20854;是否会被访问。此外,如果该缓存项如初?#20013;?#31354;闲了有一?#31181;櫻?#23427;也会被从缓存中移除。

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

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

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

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

    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);

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

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

    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 是一个枚举类型,它维护者各种可能的删除原因,如过期,删除以及替换。

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

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

    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。?#32531;?#36339;转到 /Home/Show,并不停地刷新浏览器。在某些时间点,由于其 AbsoluteExpiration 设置之后,时间戳项目将会过期。你会看到这样的 callbackMessage:

     9. 你可以设置缓存项的优先级

      正如你可以设置缓存项的到期策略一样,你还可以为缓存项赋予优先级。如果服务器内存紧缺的话,就会基于此优先级对缓存项进行清理以回收内存。 想要设置优先级的话,就要再一次用到 MemoryCacheEntryOptions。

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

      MemoryCacheEntryOptions 的 Priority 属性让你可以使用 CacheItemPriority 枚举来设置缓存项的优先?#24230;?#20540;。可选的值有 Low,Normal,High 以及 NeverRemove。

     10. 你可以设置多个缓存项之间的?#35272;?#20851;系

      你还可以对一组缓存项目之间的?#35272;?#20851;?#21040;?#34892;设置,例如在删除一个缓存项时,所有?#35272;?#30340;项也会被删除。 要是你想要了解它是如何工作的,可以像下面这样对 Index()这个 action 做一下修?#27169;?/p>

    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();
    }

      代码首先创建了一个 CancellationTokenSource 对象,该对象被存储为一个独立的缓存项 cts。?#32531;?#20687;之前那样创建出 MemoryCacheEntryOptions 对象。这时候调用 MemoryCacheEntryOptions 的  AddExpirationToken() 方法来指定过期令牌。我们不会在这里?#25945;?CancellationChangeToken 的细节。可以这样理解,过期令牌能让你有权利让一个缓存项过期。如果令牌处于活动状态的话,则缓存项就会在缓存中维持,而如果令牌被取消掉了,则该缓存项就将从缓存中删除掉。一旦缓存项从缓存中删除掉了,MyCallback 就像之前一样被调用。之后代码又创建了两个缓存项—— key1 和 key2。在添加这两个缓存项时,Set() 的第三个参数将基于之前所创建的 cts 对象传递一个 CancellationChangeToken。

      这样做就意味着这里我们有了三个键 - timestamp 是主键,而 key1 和 key2 则?#35272;?#20110; timestamp。当 timestamp 被删除时,key1 和 key2 也应该被删除掉。要删除 timestamp,你需要在代码中的某个地方取消其令牌。我们可以单独的一个 action(Remove())中进行这样的操作。

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

      这里我们先获取到之前存储的 CancellationTokenSource 对象,并调用它的 Cancel() 方法。这样做会把 timestamp,key1 以及 key2 都删除掉。 你可以通过在 Show() 这个 action 中获取一下所有这三个键来确认它们是否已经被删除掉了。

      为了测试这个例子,运行应用程序并导航至 /Home/Index。?#32531;?#20877;导航至 /Home/Show,并检查所有这三个键值是否按预期显示了出来。?#32531;?#23548;航至 /Home/ Remove,浏览器将被重定向回 /Home/Show。由于 Remove() 取消了令牌,所有的键都已经被删除调了,而现在 Show 视图会将删除的原因(TokenExpired)显示出来,如下所示:

      到目前为止就是这些了!笔耕不辍!

      原文地址:http://www.binaryintellect.net/articles/a7d9edfd-1f86-45f8-a668-64cc86d8e248.aspx?utm_source=tuicool&utm_medium=referral

    QQ群:WEB开发者官方群(515171538),验证消息:10000
    微信群:?#26377;?#32534;微信 849023636 邀请您加入,验证消息:10000
    提示:更多精彩内容关注微信公众号:全栈开发者中?#27169;╢sder-com)
    网友评论(共0条评论) 正在载入评论......
    理智评论文明上网,拒绝恶意谩骂 发表评论 / 共0条评论
    登录会员中心
    大乐透彩票预测
    <li id="2aw4k"></li>
  • <div id="2aw4k"><tr id="2aw4k"></tr></div>
  • <div id="2aw4k"><tr id="2aw4k"></tr></div>
    <center id="2aw4k"><small id="2aw4k"></small></center><center id="2aw4k"><small id="2aw4k"></small></center>
    <li id="2aw4k"></li>
  • <div id="2aw4k"><tr id="2aw4k"></tr></div>
  • <div id="2aw4k"><tr id="2aw4k"></tr></div>
    <center id="2aw4k"><small id="2aw4k"></small></center><center id="2aw4k"><small id="2aw4k"></small></center>
    欢乐生肖欢乐二 体育彩票走势图大乐透 排列5推算与估计 极速11选5是否正规 广西快乐十分怎么预测 小蘋果〗火爆四肖中特 nba比分推存 彩票软件567最新版 河南快3走势图今天快3 北京pk10七码全年可用 心水16码中特免费公开 山西快乐十分前三组中了多少钱 江苏十一选五前三直选 七星彩走势图删除 辽宁11选5复式玩法