C#系列之聊聊.Net Core的InMemoryCache
這兩天在看.net core的in memory cache,這里記錄一下用法,主要涉及MemoryCache的Get/Set/Expire/Flush。
首先我們先用dotnet命令創建一個mvc的項目,這里我們將使用postman來請求server,
| 1 | 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作為參數,如果找到則返回找到的值,若找不到則返回空
現在我們可以在命令行里輸入
| 12 | dotnet restoredotnet run |
來啟動web項目,之后我們可以通過
| 1 | 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???LowNeverRemoveNormal |
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緩存了,地址是:
| 1 | 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); |
| EvictionReasonNone = 0,Removed = 1,? 緩存項被Remove()方法移除Replaced = 2,? 緩存項被更新Expired = 3,? 緩存項超時TokenExpired = 4, 緩存由token觸發超時Capacity = 5 緩存空間不足 |
因此我們需要在callback里根據需要判斷緩存是因為什么原因被移除,才能避免意外的回調觸發。
原文地址:?https://www.cnblogs.com/xiandnc/p/9517017.html
.NET社區新聞,深度好文,歡迎訪問公眾號文章匯總 http://www.csharpkit.com
總結
以上是生活随笔為你收集整理的C#系列之聊聊.Net Core的InMemoryCache的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Asp.Net Core 2.2.0-p
- 下一篇: c# char unsigned_dll