之前給API接口寫緩存基本都是這樣寫代碼:html
// redis key var bookRedisKey = ConstRedisKey.RecommendationBooks.CopyOne(bookId); // 獲取緩存數據 var cacheBookIds = _redisService.ReadCache<List<string>>(bookRedisKey); if (cacheBookIds != null) { // return } else { // 執行另外的邏輯獲取數據, 而後寫入緩存 }
而後把這一坨坨代碼都散落在每一個地方。redis
某一天,忽然想起我這邊的緩存基本時間都差很少,並且都是給Web API用的,緩存
直接在API層支持緩存不就完事了。ide
因此, 這裏用什麼來作呢。this
在.NET Core Web API這裏的話, 兩種思路:Middleware 或者ActionFilter.spa
不瞭解的同窗能夠看下面的文檔:code
ASP.NET Core 中文文檔 第四章 MVC(4.3)過濾器htm
ASP.NET Core 中文文檔 第三章 原理(2)中間件中間件
基於我這邊只是部分接口支持緩存的話, 直接仍是用ActionFilter實現就能夠.blog
沒撒說的, 直接上代碼.
using System; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using Newtonsoft.Json.Linq; namespace XXXAPI.Filters { public class DefaultCacheFilterAttribute : ActionFilterAttribute { // 這個時間用於給子類重寫,實現不一樣時間級別的緩存 protected TimeSpan _expireTime; // redis讀寫的類,沒撒看的 private readonly RedisService _redisService; public DefaultCacheFilterAttribute(RedisService redisService) { _redisService = redisService; } public override void OnActionExecuting(ActionExecutingContext context) { if (context.HttpContext.Request.Query.ContainsKey("refresh")) { return; } KeyConfig redisKey = GetRequestRedisKey(context.HttpContext); var redisCache = _redisService.ReadCache<JToken>(redisKey); if (redisCache != null) { context.Result = new ObjectResult(redisCache); } return; } public override void OnActionExecuted(ActionExecutedContext context) { KeyConfig redisKey = GetRequestRedisKey(context.HttpContext); var objResult = (ObjectResult)context.Result; if (objResult == null) { return; } var jToken = JToken.FromObject(objResult.Value); _redisService.WriteCache(redisKey, jToken); } private KeyConfig GetRequestRedisKey(HttpContext httpContext) { var requestPath = httpContext.Request.Path.Value; if (!string.IsNullOrEmpty(httpContext.Request.QueryString.Value)) { requestPath = requestPath + httpContext.Request.QueryString.Value; } if (httpContext.Request.Query.ContainsKey("refresh")) { if (httpContext.Request.Query.Count == 1) { requestPath = requestPath.Replace("?refresh=true", ""); } else { requestPath = requestPath.Replace("refresh=true", ""); } } // 這裏也就一個redis key的類 var redisKey = ConstRedisKey.HTTPRequest.CopyOne(requestPath); if (_expireTime != default(TimeSpan)) { redisKey.ExpireTime = _expireTime; } return redisKey; } } public static class ConstRedisKey { public readonly static KeyConfig HTTPRequest = new KeyConfig() { Key = "lemon_req_", ExpireTime = new TimeSpan(TimeSpan.TicksPerMinute * 30), DBName = 5 }; } public class KeyConfig { public string Key { get; set; } public TimeSpan ExpireTime { get; set; } public int DBName { get; set; } public KeyConfig CopyOne(string state) { var one = new KeyConfig(); one.DBName = this.DBName; one.Key = !string.IsNullOrEmpty(this.Key) ? this.Key + state : state; one.ExpireTime = this.ExpireTime; return one; } } }
而後使用的地方, 直接給Controller的Action方法加上註解便可.
如:
[HttpGet("v1/xxx/latest")] [ServiceFilter(typeof(DefaultCacheFilterAttribute))] public IActionResult GetLatestList([FromQuery] int page = 0, [FromQuery]int pageSize = 30) { return Ok(new { data = _service.LoadLatest(page, pageSize), code = 0 }); }
完事...
哦, 記得在Startup.cs注入 DefaultCacheFilterAttribute.
這個注入就不用我來寫的吧.
美中不足的地方在於暫時還不知道怎麼直接在註解上面支持自定義緩存時間,
湊合先用了.
完結, 拜.....