C#系列之聊聊.Net Core的InMemoryCache

来源:https://www.cnblogs.com/xiandnc/archive/2018/08/22/9517017.html
-Advertisement-
Play Games

作者:暴王 個人博客:http://www.boydwang.com/2017/12/net core in memory cache/ 這兩天在看.net core的in memory cache,這裡記錄一下用法,主要涉及MemoryCache的Get/Set/Expire/Flush。 首先我 ...


作者:暴王
個人博客: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里根據需要判斷緩存是因為什麼原因被移除,才能避免意外的回調觸發。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 裝箱:裝箱在值類型向引用類型轉換時發生。值類型是要放在棧上的,引用類型它需要放在堆上。 拆箱:拆箱在引用類型向值類型轉換時發生。 臟讀:臟讀是針對事物操作來說的,只有在A,B兩個事物時,A事物對一個值做了修改操作,但是沒有提交事物,這個時候,B事物讀取了A事物的修改值,但是A事物有對這個修改做了取消 ...
  • 引用:https://www.cnblogs.com/dacongge/p/6957074.html 1、JObject:基本的json對象 2、JObject:嵌套子對象(JObject嵌JObject) 3、JArray:基本json對象中的數組 4、JArray: 多個json對象數組 5、J ...
  • 真覺得自己的知識面還是比較窄,在此之前,居然還不知道SqlLocalDb。 SqlLocalDb是啥?其實就是簡化SQL Server的本地資料庫,可以這樣子說,SQL Server既可以作為遠程,也可以做本地, 而SqlLocalDb只能作為本地使用。說的直接一點,SqlLocalDb就是一個輕量 ...
  • 項目屬性-->生成-->允許不安全代碼勾上。 代碼: /// <summary> /// 反色處理 /// </summary> private Bitmap Inverse(Bitmap bmp) { BitmapData srcdat = bmp.LockBits(new Rectangle(P ...
  • 同大陸身份證驗證一樣,該部分是按照國家增值稅發票代碼的定製規則,進行發票代碼驗證,如果需要查驗發票信息是否正確,應該通過第三方介面(大約一毛錢查驗一次),或者直接上 "國家稅務總局全國增值稅發票查驗平臺" 進行查驗。 目前能識別的增值稅發票代碼包含以下幾類: 增值稅專用發票 , 增值稅普通發票(紙質 ...
  • 上一篇文章中介紹了關於設置Excel條件格式,包括基於單元格值、自定義公式等應用條件格式、應用數據條條件類型格式、刪除條件格式等內容。在本篇文章中將繼續介紹C# 設置條件格式的方法。 要點概述: 1. 應用條件格式用於高亮重覆、唯一數值 2. 應用條件格式用於高亮峰值(最高、最低) 3. 應用條件格 ...
  • 在本教程中,我們來學習如何進行分組。 在 書籍管理系統的“關於”頁上,將顯示每個出版社有多少書籍。 這要求在分組上再進行分組和簡單計算。 要完成此操作,需要執行以下操作: 創建一個視圖模型類,該視圖類是需要傳遞到該視圖的數據的抽象。 修改關於視圖。 ...
  • C#/WPF/WinForm/.NET程式代碼實現軟體程式開機自動啟動的兩種常用方法函數的示例與實例帶詳細註釋 方法一:將軟體的快捷方式創建到電腦的自動啟動目錄下(不需要管理員許可權) 1.必要引用 2.代碼實現-只需要調用SetMeAutoStart(bool onOff)方法就可以了,參數onO ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...