1. <em id="2qvri"><tr id="2qvri"></tr></em>
      1. 首頁»ASP.NET»關于 ASP.NET Core 內存緩存你需要知道的 10 點

        關于 ASP.NET Core 內存緩存你需要知道的 10 點

        來源:oschina 發布時間:2017-06-23 閱讀次數:

          緩存機制的主要目的是提高應用程序的性能。作為 ASP.NET 開發人員,你可能會意識到 ASP.NET Web 窗體以及 ASP.NET MVC 可以使用 Cache 對象緩存應用程序的數據。這通常被稱為服務器端數據緩存,并且常作為框架的內置功能。雖然 ASP.NET Core 中并沒有這樣的 Cache 對象,但是你可以很容易地實現內存緩存。本文將向你說明如何實現。

          在進一步閱讀之前,你先創建一個基于 Web 應用程序項目模板的新的 ASP.NET Core 應用程序。

          然后按照下面提到的步驟逐一構建和測試由內存緩存提供的各種功能。

         1. 內存緩存需要在啟動類 Startup 中啟用一下

          不同于 ASP.NET Web 窗體和 ASP.NET MVC,ASP.NET Core 沒有內置的 Cache 對象,可以拿來在控制器里面直接使用。 這里,內存緩存時通過依賴注入來啟用的,因此第一步就是在 Startup 類中注冊內存緩存的服務。如此,就得打開 Startup 類然后定位到 ConfigureServices() 方法,像下面這樣修改 ConfigureServices() 方法:

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

          為了向你的應用程序加入內存緩存能力,你需要在服務集合上調用 AddMemoryCache() 方法。采用這種辦法就可以讓一個內存緩存(它是一個 IMemoryCache 對象)的默認實現可以被注入到控制器中去。

         2. 內存緩存使用依賴注入來注入緩存對象

          然后打開 HomeController 并對其進行修改,如下所示:

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

          如你所見,上述代碼聲明了一個 ImemoryCache 的私有變量。該變量會被構造器中被賦值。構造器會通過 DI(依賴注入)接收到緩存參數,然后被存儲在本地變量總,提供后續使用。

         3. 你可以使用 Set() 方法來在緩存中存東西

          等你有了這個 IMemoryCache 對象,就可以讀取或者向它寫入數據了。向緩存寫入數據項是相當直接的。

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

          上述代碼在 Index() 這個 action 中設置了一個緩存項。這是通過使用 IMemoryCache 的 Set<T>() 來完成的。Set() 方法的第一個參數是鍵名,用來標識該數據項。第二個參數是鍵的取值。在此例中,我們存儲一個字符串的鍵和一個字符串的值,而你也可以存儲其它類型 (原生以及自定義的類型) 的鍵值對。

         4. 你可以使用 Get 方法來從緩存中獲取到一個數據項

          等你向緩存中添加好了數據,也許會想要在應用程序的其它地方去獲取到該數據,可以用 Get() 來做到。如下代碼會告訴你如何來做這件事情。

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

          上述代碼從 HomeController 的另外一個action(Show)那里獲取到了一個緩存的數據項。Get() 方法會指定數據項的類型以及它的鍵名。如果該數據項存在的話,就會被返回并且被賦值給 timestamp 這個字符串變量。然后這個 timestamp 的值就會被傳遞給 Show 視圖。

          Show 視圖只是簡單地輸出了 timestamp 的值,如下所示:

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

          為了對目前為止你所寫的代碼進行一下測試,請運行應用程序。首先將瀏覽器導航至 /Home/Index ,這樣 timestamp 鍵就會被賦值。然后導航至 /Home/Show 并查看 timestamp 值是否會輸出。下圖所示是 Show() 這個 action 運行起來的一個例子。

         5. 你可以使用 TryGet() 來檢查緩存中是否存在特定的鍵值

          如果你觀察前面的示例,會發現每次你導航至 /Home/Index 的時候, 都會有一個新的 timestamp 被賦值給了緩存項。這是因為我們并沒有對此進行檢查,規定只有在數據項不存在的時候才賦值。許多時候你都會想要這樣做的。這里有兩種辦法可以在 Index() 這個 action 里面來做這樣的檢查。我們把兩種辦法都在下面列了出來。

        //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() 方法,這一次它被拿來跟 if 塊一起用。如果 Get() 不能在緩存中找到指定的數據項,IsNullOrEmpty() 就會返回 true。而只有這時候 Set() 才會被調用,一次來添加數據項。

          第二種辦法更加優雅一點。它使用 TryGet() 方法來獲取一個數據項。TryGet() 方法會返回一個布爾值來指明數據項有沒有被找到。實際的數據項可以使用一個輸出參數拉取出來。如果 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() 方法將檢查時間戳的鍵值是否存在。如果是,現有值將被賦值給局部變量。否則,將根據第二個參數中指定的邏輯創建一個新條目并將其添加到緩存中。

          為了測試此代碼,請直接運行 /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 的對象,然后將它的 AbsoluteExpiration 屬性設置為從此刻到一分鐘之后的一個 DateTime 值,它還將 SlidingExpiration 屬性設置為一分鐘。這些值都指定了該緩存項會在一分鐘之后從緩存移除,不管其是否會被訪問。此外,如果該緩存項如初持續空閑了有一分鐘,它也會被從緩存中移除。

          等你將 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 的實例 (用 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。然后跳轉到 /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 枚舉來設置緩存項的優先級取值。可選的值有 Low,Normal,High 以及 NeverRemove。

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

          代碼首先創建了一個 CancellationTokenSource 對象,該對象被存儲為一個獨立的緩存項 cts。然后像之前那樣創建出 MemoryCacheEntryOptions 對象。這時候調用 MemoryCacheEntryOptions 的  AddExpirationToken() 方法來指定過期令牌。我們不會在這里探討 CancellationChangeToken 的細節。可以這樣理解,過期令牌能讓你有權利讓一個緩存項過期。如果令牌處于活動狀態的話,則緩存項就會在緩存中維持,而如果令牌被取消掉了,則該緩存項就將從緩存中刪除掉。一旦緩存項從緩存中刪除掉了,MyCallback 就像之前一樣被調用。之后代碼又創建了兩個緩存項—— key1 和 key2。在添加這兩個緩存項時,Set() 的第三個參數將基于之前所創建的 cts 對象傳遞一個 CancellationChangeToken。

          這樣做就意味著這里我們有了三個鍵 - timestamp 是主鍵,而 key1 和 key2 則依賴于 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。然后再導航至 /Home/Show,并檢查所有這三個鍵值是否按預期顯示了出來。然后導航至 /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
        微信群:加小編微信 849023636 邀請您加入,驗證消息:10000
        提示:更多精彩內容關注微信公眾號:全棧開發者中心(fsder-com)
        網友評論(共0條評論) 正在載入評論......
        理智評論文明上網,拒絕惡意謾罵 發表評論 / 共0條評論
        登錄會員中心
        江苏快3投注技巧