Существует решение с использованием заголовков HTTP "ETag", "If-None-Match".Идея заключается в использовании кода, который может дать нам ответ на вопрос: «Изменился ли ответ на действие?».Это может быть сделано, если контроллер полностью владеет определенным временем жизни данных.
Создание 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();
}
Это решение может потребовать изменения на стороне клиента.Если вы используете fetch, вы можете использовать, например, следующую библиотеку: https://github.com/export-mike/f-etag.
PS Я не указал реализацию интерфейса ITagProvider, вам нужно будет написать свою собственную.PPS Статьи о ETag и кешировании: https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching, https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag