読者です 読者をやめる 読者になる 読者になる

1.21 jigowatts

Great Scott!

ASP.NET MVCはじめました~データのキャッシュ

概要

データキャッシュの実装とテストについて調べてみました。

参考資料

ASP.NET MVCでのキャッシュについては、今のところ、キャッシュ機能をアプリケーションに注入する方法が推奨されています。

特定のキャッシュ機能の実装に依存しないようにキャッシュサービスを注入してあげれば良さそう。

環境

キャッシュサービスの実装

インターフェイスと実装。インターフェイスは必要に応じて機能を追加します。書籍のサンプルコードではSystem.Web.CachingのCacheオブジェクトを使用していましたが、System.Runtime.CachingのMemoryCacheオブジェクトに置き換えてみました。
/Framework/ICacheService.cs

public interface ICacheService
{
    Object Get(String key);
    void Set(String key, Object data);
    Object this[String key] { get; set; }
}

/Framework/AspNetCacheService.cs

public class AspNetCacheService : ICacheService
{
    private readonly MemoryCache _memoryCache;
    public AspNetCacheService()
    {
        _memoryCache = MemoryCache.Default;
    }

    public object Get(string key)
    {
        return _memoryCache[key];
    }

    public void Set(string key, object data)
    {
        _memoryCache[key] = data;
    }

    public object this[string key]
    {
        get { return _memoryCache[key]; }
        set { _memoryCache[key] = value; }
    }
}
キャッシュサービスの注入

アプリケーションの起動時にキャッシュサービスを注入するためのパブリックなRegisterCacheServiceメソッドを用意しておくと、コントローラごとにサービスを注入する必要はなく、テストもできるって訳ですね。
Global.asax.cs

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        ...

        RegisterCacheService(new AspNetCacheService());
        CacheService["StartTime"] = DateTime.Now.ToString();
    }

    private static ICacheService _internalCacheObject;

    public static void RegisterCacheService(ICacheService cacheService)
    {
        _internalCacheObject = cacheService;
    }

    public static ICacheService CacheService
    {
        get { return _internalCacheObject; }
    }
}


HomeController.cs

public class HomeController : Controller
{
    public ActionResult Index()
    {
        var data = MvcApplication.CacheService["StartTime"];
        if (data != null)
        {
            ViewBag.StartTime = (String)data;
        }

        return View();
    }
}

キャッシュサービスのテスト

テストの時はモックを用意してRegisterCacheServiceメソッドに渡してあげる感じ。
HomeControllerTests.cs

public class HomeControllerTests
{
    [TestMethod()]
    public void IndexTest_Cache()
    {
        var expected = "2017-04-15 12:00:00.000";
        var mockCacheService = new Mock<ICacheService>();
        mockCacheService.Setup(m => m["StartTime"]).Returns(expected);
        MvcApplication.RegisterCacheService(mockCacheService.Object);

        var controller = new HomeController();
        ViewResult result = controller.Index() as ViewResult;
        var actual = result.ViewBag.StartTime;

        Assert.AreEqual(expected, actual);
    }
}

実行結果

f:id:sh_yoshida:20170415173157p:plain

参考資料