寫一個特性類,用來做標記 [AttributeUsage(AttributeTargets.Method)] //只對方法有效 public class ResourceFilterAttribute : Attribute { } 我這裡使用了MemoryCache來做緩存,也可以使用字典來做,但 ...
寫一個特性類,用來做標記
[AttributeUsage(AttributeTargets.Method)] //只對方法有效
public class ResourceFilterAttribute : Attribute
{
}
我這裡使用了MemoryCache來做緩存,也可以使用字典來做,但一定要加上static,否則字典每一次請求都會new一個實例,緩存的東西就丟了
private static Dictionary<string,object> caCheDic=new Dictionary<string, object>();
過濾器代碼實現
public class ResourceFilter : IAsyncResourceFilter
{
private readonly IMemoryCache cache;
public ResourceFilter(IMemoryCache cache)
{
this.cache = cache;
}
public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next)
{
//獲取當前正在處理的控制器動作方法的相關信息,例如方法名、參數
var actionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
// 檢查當前請求是否為 Controller Action
if (actionDescriptor == null)
{
await next();
return;
}
// 檢查當前 Action 是否包含 ResourceFilterAttribute,如果沒有則繼續處理下一個中間件
if (!actionDescriptor.MethodInfo.GetCustomAttributes(typeof(ResourceFilterAttribute), true).Any())
{
await next();
return;
}
//把請求的ip和方法名當做緩存的key
var cacheKey=context.HttpContext.Connection.RemoteIpAddress.ToString()+actionDescriptor.ActionName;
//去緩存中找 如果有則直接返回
if (cache.TryGetValue(cacheKey, out IActionResult resultFromCache))
{
context.Result= resultFromCache;
return;
}
// 執行下一個中間件並獲取結果
var resultContext =await next();
// 如果結果是 IActionResult 類型,則將結果緩存起來
if (resultContext.Result is IActionResult actionResult)
{
//緩存時間
var cacheOptions = new MemoryCacheEntryOptions()
.SetSlidingExpiration(TimeSpan.FromSeconds(10));
cache.Set(cacheKey, actionResult, cacheOptions);
}
context.Result = resultContext.Result;
}
}
在program類中要註入MemoryCache
builder.Services.AddMemoryCache();
還要進行配置我們剛纔寫的篩選器
builder.Services.AddControllers().AddMvcOptions(option => {
option.Filters.Add(typeof(ResourceFilter));
});
在需要進行緩存的action頭上加上ResourceFilter特性,表示這個action的返回結果要進行緩存
[Route("api/[controller]/[action]"), ApiController]
public class TestController : ControllerBase
{
List<SysUser> sysUsers = new List<SysUser>()
{
new SysUser("admin","123"),
new SysUser("admin2","123")
};
[HttpGet, ResourceFilter]
public List<SysUser> GetUsers() { return sysUsers; }
}
public record SysUser(string loginName,string loginPwd);
進行測試,我這裡直接就是截圖的第二次請求,可以看到,請求去緩存裡面讀到了數據
還有需要註意的是,儘量不要在緩存中存儲IQuerytable和IEnumtable等具有延遲執行的類型或介面的數據,因為是延遲執行,IQuerytable和IEnumtable都是生成的sql語句,所以在使用ef時,這些數據還是會去進行資料庫操作,這樣我們的緩存也就沒有意義了。