ASP.NET MVC 5 でもキャッシュのための手段はいくつか用意されていましたが、ASP.NET Core MVC 1.0 では少し方向性が変わっています。大きく変わっているのが OutputCache 属性が無くなっていることです。
現実的にキャッシュを行う手段は ASP.NET Core MVC 1.0 では以下になります。
それぞれ特徴があるのと、MVC 5 には無かった機能なので一つずつ確認してみました。
ResponseCache
OutputCache みたいな名前の ResponseCache ですが、中身は全く異なっています。OutputCache は出力をサーバー側でキャッシュしていましたが、ResponseCache は Cache-Control ヘッダーを出力するだけです。
[ResponseCache(Duration = 10)] public IActionResult Index() { return View(); }
10 秒だけキャッシュするように設定すると、Cache-Control の max-age が設定されています。
あくまでもブラウザ側にキャッシュさせるだけなので、Ctrl+F5 などで更新するとキャッシュが無視されて、サーバーにリクエストが投げられます。
ASP.NET は Cache-Control 周りが上手くコントロールできないことが多かったですが、ASP.NET Core は基本的に開発者がコントロールできるようになっているので、挙動が分かりやすいです。
Cache Tag Helper
コンテンツ全体をキャッシュする OutputCache 的なものは RC 2 でも用意されてないですが、コンテンツ内の一部分だけをキャッシュするための Tag Helper は用意されています。
Razor では cache タグを使うだけで、その中身をキャッシュ可能です。
<p>Actual Time: @DateTime.Now.ToString()</p> <cache expires-after="TimeSpan.FromSeconds(10)"> <p>Cached Time: @DateTime.Now.ToString()</p> </cache>
日付を扱う単純なサンプルですが、これを実行するとキャッシュされていることが確認できます。
実際にはページコンテンツ全体をキャッシュするよりも、一部分だけをキャッシュしたいことのが多いと思うので、Cache Tag Helper は便利に扱えそうです。
中に View Components の呼び出しを入れると、MVC 5 などで可能だった Action/RenderAction を使った部分的なキャッシュを行えるようになってます。
Memory Cache
.NET Framework 4 からは System.Runtime.Caching が追加されて、MemoryCache を使えるようになりましたが、ObjectCache のオーバーライドめんどくさくて大変でした。
ASP.NET Core 1.0 では Microsoft.Extension.Caching が追加されて、シンプルですが拡張性の高いインターフェースを備えるようになりました。
Cache in-memory in ASP.NET Core | Microsoft Learn
公式で In Memory 以外にも Redis と SQL Server を使えるようになっているのもポイントが高いです。
public void ConfigureServices(IServiceCollection services) { services.AddMemoryCache(); }
使う前にはちゃんと ConfigureServices で AddMemoryCache メソッドを呼び出しておきます。
インスタンスを取得するには、コンストラクタで IMemoryCache を受け取るようにするだけです。
public class HomeController : Controller { public HomeController(IMemoryCache memoryCache) { _memoryCache = memoryCache; } private IMemoryCache _memoryCache; public async Task<IActionResult> Index() { var data = await _memoryCache.GetOrCreateAsync("KEY", async entry => { await Task.Delay(1000); // 5 秒だけキャッシュする entry.AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(5); return DateTime.Now.ToString(); }); ViewData["Message"] = data; return View(); } }
非同期対応のキャッシュインターフェースはこれまで公式で提供されていなかったので、自作した人が多いと思います。Task と async が使える拡張メソッドが用意されているので、かなり便利です。
Memory Cache はデータベースや、ネットワーク経由で取得したデータのキャッシュ向けでしょうね。