Есть ли способ использовать какой-либо IDistributedCache в качестве ResponseCache в ядре. net? - PullRequest
2 голосов
/ 01 мая 2020

Я хочу кешировать ответы от API на DistributedSqlServerCache. По умолчанию ResponseCaching использует только кэш памяти. Есть конструктор, который позволяет настроить, какой кеш использовать, но он внутренний.

Я написал фильтр. Если ответ не кэшируется, а http-ответ в порядке, а ActionResult является ObjectActionResult, он сериализует значение как JSON и сохраняет его в SQL кэш. Если ответ кэшируется, он десериализует его и устанавливает результат как результат OkObject с десериализованным объектом.

Он работает нормально, но у него есть некоторые неуклюжие вещи (например, чтобы использовать атрибут, вы должны указать тип, который будет де / сериализован, с помощью typeof ()).

Есть ли способ кешировать ответы в распределенный кэш sql, который не требует от меня взлома моего собственного наиболее работающего решения?

Другой вариант - скопировать и вставить netcore ResponseCacheMiddleWare и изменить его для использования другого кэша. Я мог бы даже сделать это пакетом nuget.

Существуют ли другие решения?

Вот фильтр, который я собрал (упрощенный для отображения)

namespace Api.Filters
{
    /// <summary>
    /// Caches the result of the action as data.
    /// The action result must implement <see cref="ObjectResult"/>, and is only cached if the HTTP status code is OK.
    /// </summary>
    public class ResponseCache :  IAsyncResourceFilter
    {
        public Type ActionType { get; set; }

        public ExpirationType ExpirationType;

        private readonly IDistributedCache cache;

        public ResponseCache(IDistributedCache cache)
        {
            this.cache = cache;
        }

        public async Task OnResourceExecutionAsync(ResourceExecutingContext executingContext, ResourceExecutionDelegate next)
        {
            var key = getKey(executingContext);
            var cachedValue = await cache.GetAsync(key);

            if (cachedValue != null && executingContext.HttpContext.Request.Query["r"] == "cache")
            {
                await cache.RemoveAsync(key);
                cachedValue = null;
            }

            if (cachedValue != null)
            {
                executingContext.Result = new OkObjectResult(await fromBytes(cachedValue));
                return;
            }

            var executedContext = await next();

            // Only cache a successful response.
            if (executedContext.HttpContext.Response.StatusCode == StatusCodes.Status200OK && executedContext.Result is ObjectResult result)
            {
                await cache.SetAsync(key, await toBytes(result.Value), getExpiration());
            }
        }

        private async Task<byte[]> toBytes(object value)
        {
            using var stream = new MemoryStream();

            await JsonSerializer.SerializeAsync(stream, value, ActionType);

            return stream.ToArray();
        }

        private async Task<object> fromBytes(byte[] bytes)
        {
            using var stream = new MemoryStream(bytes);
            using var reader = new BinaryReader(stream, Encoding.Default, true);

            return await JsonSerializer.DeserializeAsync(stream, ActionType);
        }
    }

    public class ResponseCacheAttribute : Attribute, IFilterFactory
    {
        public bool IsReusable => true;

        public ExpirationType ExpirationType;

        public Type ActionType { get; set; }

        public ResponseCacheAttribute(params string[] queryParameters)
        {
            this.queryParameters = queryParameters;
        }

        public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
        {
            var cache = serviceProvider.GetService(typeof(IDistributedCache)) as IDistributedCache;

            return new ResponseCache(cache)
            {
                ExpirationType = ExpirationType,
                ActionType = ActionType
            };
        }
    }
}

1 Ответ

0 голосов
/ 07 мая 2020

В итоге я сделал пакет nuget , полученный на github . См. эту проблему , чтобы узнать, почему был создан новый пакет.

...