- 建立一個
CacheActionFilter
class,實作 Attribute
和 IAsyncActionFilter
public class CacheActionFilter : Attribute, IAsyncActionFilter
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
await next();
}
}
- 可以拿到傳入 action 的參數和它的名稱當成快取的 key
public class CacheActionFilter : Attribute, IAsyncActionFilter
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
var args = context.ActionArguments.Select(a => $"{JsonConvert.SerializeObject(a.Value)}");
var arg = string.Join(",", args);
var cacheKey = $"{context.ActionDescriptor.DisplayName}-{arg}";
await next();
}
}
- 可以拿到 response 之後使用
MemoryCache
快取起來- 這裡假設 API 的返回都只有
OKObjectResut
- 為了之後方便使用,
IMemoryCache
直接從 RequestServices
拿
public class CacheActionFilter : Attribute, IAsyncActionFilter
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
var args = context.ActionArguments.Select(a => $"{JsonConvert.SerializeObject(a.Value)}");
var arg = string.Join(",", args);
var cacheKey = $"{context.ActionDescriptor.DisplayName}-{arg}";
await next();
if (response.Result is OkObjectResult result)
{
var memory = response.HttpContext.RequestServices.GetService<IMemoryCache>();
memory.Set(cacheKey, result.Value);
}
}
}
- 使用
MemoryCache
要記得在 startup
註冊
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddMemoryCache();
}
- 因為已經有把 response 快取了,所以可以在執行
next
之前判斷,如果有快取就直接返回快取,沒有的話就再執行 next
public class CacheActionFilter : Attribute, IAsyncActionFilter
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
var args = context.ActionArguments.Select(a => $"{JsonConvert.SerializeObject(a.Value)}");
var arg = string.Join(",", args);
var cacheKey = $"{context.ActionDescriptor.DisplayName}-{arg}";
var memoryCache = context.HttpContext.RequestServices.GetService<IMemoryCache>();
if (memoryCache.TryGetValue(cacheKey, out object cacheResult))
{
context.Result = new OkObjectResult(cacheResult);
return;
}
var response = await next();
if (response.Result is OkObjectResult result)
{
memoryCache.Set(cacheKey, result.Value);
}
}
}
- 因為現在是有快取就不執行,應該是有點奇怪,應該要改成由外面決定快取的時間,如果超過一定的時間,還是要執行會比較合理
public class CacheActionFilter : Attribute, IAsyncActionFilter
{
private readonly int _duration;
public CacheActionFilter(int duration)
{
_duration = duration;
}
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
var args = context.ActionArguments.Select(a => $"{JsonConvert.SerializeObject(a.Value)}");
var arg = string.Join(",", args);
var cacheKey = $"{context.ActionDescriptor.DisplayName}-{arg}";
var memoryCache = context.HttpContext.RequestServices.GetService<IMemoryCache>();
if (memoryCache.TryGetValue(cacheKey, out object cacheResult))
{
context.Result = new OkObjectResult(cacheResult);
return;
}
var response = await next();
if (response.Result is OkObjectResult result)
{
memoryCache.Set(cacheKey, result.Value, TimeSpan.FromSeconds(_duration));
}
}
}
- 實際測試使用,一直 refresh 的話,時間每隔 5 秒才會變
[HttpGet]
[CacheActionFilter(5)]
public ActionResult<string> Get(string name)
{
return Ok($"{name} - {DateTime.Now.ToString()}");
}