2021年12月10日 星期五

asp.net core cache

ASP.NET Core 的 ResponseCache 觸發伺服器端快取的條件尤為嚴格,限制很多

為了節省伺服器的運算成本,所以可以實作一個ResultFilter來快取頁面

這邊是採用本機MemoryCache,當然也可以改用Redis或者其他Cache Server

首先在Startup.cs加入services.AddMemoryCache();

public void ConfigureServices(IServiceCollection services)
{
    services.AddMemoryCache();
    services.AddControllers();
}

在建立一個CacheResultFilter

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.Memory;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace WebApplication2
{
    public class CacheResultFilter : ResultFilterAttribute
    {
        private readonly int _expiration;
        public CacheResultFilter(int expirationMs)
        {
            _expiration = expirationMs;
        }
        public override void OnResultExecuting(ResultExecutingContext context)
        {            
            var controller = context.RouteData.Values["Controller"].ToString();
            var action = context.RouteData.Values["Action"].ToString();
            var method = context.HttpContext.Request.Method;
            var queryStrings = new List<string>();
            if (context.HttpContext.Request.Query.Count > 0)
            {
                context.HttpContext.Request.Query.ToList()
                   .ForEach(kv =>
                   {
                       queryStrings.Add(kv.Key);
                       queryStrings.Add(kv.Value);
                   });
            }
            var key = generateCacheKey(action, method, queryStrings.ToArray());
            var cache = context.HttpContext.RequestServices.GetService(typeof(IMemoryCache));
            if (cache == null)
            {
                base.OnResultExecuting(context);
                return;
            }
            var cacheValue = (cache as IMemoryCache)?.Get(key);
            if (cacheValue != null)
            {
                context.Result =
                    new ObjectResult(JsonConvert.DeserializeObject(cacheValue.ToString()));
            }
            else
            {
                var objResult = context.Result as ObjectResult;
                var json = JsonConvert.SerializeObject(objResult.Value);
                (cache as IMemoryCache)?.Set(key, json, TimeSpan.FromMilliseconds(_expiration));
            }
            base.OnResultExecuting(context);
        }

        private string generateCacheKey(string action,string method,string[] queryStrings)
        {
            var key = string.Format("{0}_{1}_{2}", action, method, string.Join("_", queryStrings));
            return key;
        }
    }
}

所以在Controller的這樣使用

using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace WebApplication2.Controllers { [ApiController] [Route("[controller]")] public class ExampleController : ControllerBase { [HttpGet] [CacheResultFilter(5000)] public DateTime Get() { return DateTime.Now; } } }
這邊Get掛上了CacheResultFilter設定快取5秒

沒有留言:

張貼留言