我正在使用以下属性[ResponseCache(Duration = 60)]
来缓存特定的GET请求,该请求在.NET Core的后端中经常被调用。
一切正常,除了在60秒内数据库中的某些数据发生更改时不重新加载缓存之外。
我必须设置一个特定的指令来重新加载/更新缓存吗? link
我的控制器中的示例代码段:
[HttpGet]
[ResponseCache(Duration = 60)]
public ActionResult<SomeTyp[]> SendDtos()
{
var dtos = _repository.QueryAll();
return Ok(dtos);
}
答案 0 :(得分:1)
有一个使用“ ETag”,“ If-None-Match” HTTP标头的解决方案。这个想法使用的代码可以为我们提供以下问题的答案:“动作响应是否已更改?”。 如果控制器完全拥有特定的数据寿命,则可以这样做。
创建ITagProvider:
public interface ITagProvider
{
string GetETag(string tagKey);
void InvalidateETag(string tagKey);
}
创建动作过滤器:
public class ETagActionFilter : IActionFilter
{
private readonly ITagProvider _tagProvider;
public ETagActionFilter(ITagProvider tagProvider)
{
_tagProvider = tagProvider ?? throw new ArgumentNullException(nameof(tagProvider));
}
public void OnActionExecuted(ActionExecutedContext context)
{
if (context.Exception != null)
{
return;
}
var uri = GetActionName(context.ActionDescriptor);
var currentEtag = _tagProvider.GetETag(uri);
if (!string.IsNullOrEmpty(currentEtag))
{
context.HttpContext.Response.Headers.Add("ETag", currentEtag);
}
}
public void OnActionExecuting(ActionExecutingContext context)
{
var uri = GetActionName(context.ActionDescriptor);
var requestedEtag = context.HttpContext.Request.Headers["If-None-Match"];
var currentEtag = _tagProvider.GetETag(uri);
if (requestedEtag.Contains(currentEtag))
{
context.HttpContext.Response.Headers.Add("ETag", currentEtag);
context.Result = new StatusCodeResult(StatusCodes.Status304NotModified);
}
}
private string GetActionName(ActionDescriptor actionDescriptor)
{
return $"{actionDescriptor.RouteValues["controller"]}.{actionDescriptor.RouteValues["action"]}";
}
}
初始化Startup
类中的过滤器:
public void ConfigureServices(IServiceCollection services)
{
// code above
services.AddMvc(options =>
{
options.Filters.Add(typeof(ETagActionFilter));
});
services.AddScoped<ETagActionFilter>();
services.AddSingleton<ITagProvider, TagProvider>();
// code below
}
在控制器中的某处(在您修改数据的地方)使用InvalidateETag
方法:
[HttpPost]
public async Task<ActionResult> Post([FromBody] SomeType data)
{
// TODO: Modify data
// Invalidate tag
var tag = $"{controllerName}.{methodName}"
_tagProvider.InvalidateETag(tag);
return NoContent();
}
此解决方案可能需要更改客户端。如果使用提取,则可以使用例如以下库:https://github.com/export-mike/f-etag。
P.S。我没有指定ITagProvider接口的实现,您将需要编写自己的接口。 P.P.S.有关ETag和缓存的文章:https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching,https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag