有没有一种方法可以在.net核心中使用任何IDistributedCache作为ResponseCache



我想将API的响应缓存到DistributedSqlServerCache。默认的ResponseCaching仅使用内存缓存。有一个构造函数允许配置要使用的缓存,但它是内部的。

我写了一个过滤器。如果响应未缓存,http响应为OK,ActionResult为ObjectActionResult,则它会将值序列化为JSON并将其保存到SQL缓存中。如果缓存了响应,它会对其进行反序列化,并将结果设置为具有取消序列化对象的OkObject结果。

它工作正常,但也有一些笨拙的地方(比如,要使用属性,必须使用typeof((指定将被反序列化的类型(。

有没有一种方法可以将响应缓存到分布式sql缓存中,而不需要我自己破解自己的主要工作解决方案?

另一种选择是复制netcore ResponseCacheMiddleWare,并将其修改为使用困难缓存。我甚至可以把它做成一个裸体包。

还有其他解决方案吗?

这是我放在一起的过滤器(为了显示目的而简化(

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
};
}
}
}

最后,我制作了一个源于github的nuget包。关于为什么要制定新的一揽子计划,请参阅本问题。

相关内容

  • 没有找到相关文章

最新更新