在大流量網站,為了減少資料庫的負擔,很多都會選擇用 Redis 做為快取的 server。而 ServiceStack 我覺得它提供的 library 相當好用,尤其它提供了一個叫 ICacheClient 的介面,除了 Redis,也可依需求換成別的種類,例如放在 Azure 上的快取 server。

以下連結為本篇文章的範例位置:

範例下載

以下示範 ICacheClient 的使用方式,首先新增 Redis 的連線字串:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "ConnectionStrings": {
    "RedisConnection": "redis://localhost:6379?db=15"
  },
  "AllowedHosts": "*"
}

接下來新增兩個類別:

namespace RedisCacheWebAP.CacheLib
{
    public abstract class BaseCacheClass
    {
        public abstract void Init(IConfiguration configuration);

        public abstract ICacheClient GetCacheClient();
    }
    
    public class RedisCacheClass : BaseCacheClass
    {
        private static RedisManagerPool RedisManagerPool = null;

        public override void Init(IConfiguration configuration)
        {
            if (RedisManagerPool == null)
            {
                RedisManagerPool = new RedisManagerPool(configuration.GetConnectionString("RedisConnection"));
            }
        }

        public override ICacheClient GetCacheClient()
        {
            return RedisManagerPool.GetCacheClient();
        }
    }
}

一個是抽象類別,方便之後抽換快取方式,別一個則是使用到 Redis 相關類別,像是建一個 connection pool 及取得 cache client 的 method。

最後在 Startup.cs 做註冊:

public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped(typeof(ICacheClient), (x =>
    {
        BaseCacheClass cacheClass = new RedisCacheClass();
        cacheClass.Init(Configuration);
        return cacheClass.GetCacheClient();
    }));

    services.AddControllersWithViews();
}

最後在 controller 就可以透過 DI 的方式取得 ICacheClient:

public class HomeController : Controller
{
    private readonly ILogger<HomeController> _logger;
    private readonly ICacheClient _cacheClient;

    public HomeController(ILogger<HomeController> logger, ICacheClient cacheClient)
    {
        _logger = logger;
        _cacheClient = cacheClient;
    }

    [HttpGet]
    public IActionResult TestCache()
    {
        DateTime? dt = _cacheClient.Get<DateTime?>("time");
        if (dt == null)
        {
            dt = DateTime.Now;
            _cacheClient.Set<DateTime?>("time", dt.Value, TimeSpan.FromMinutes(1));
        }

        return Content(dt.Value.ToString());
    }
}

參考資料