Принудительная перезагрузка ResponseCache в .NET Core 2.1 при изменении данных запроса - PullRequest
0 голосов
/ 23 ноября 2018

Я использую следующий атрибут [ResponseCache(Duration = 60)] для кэширования определенного запроса GET, который часто вызывается в моем бэкэнде в .NET Core.

Все работает нормально, за исключением того, что кэш не перезагружается, когда некоторыеданные в базе данных изменились за 60 секунд.
Есть ли какая-то особая директива, которую я должен установить для перезагрузки / обновления кэша? ссылка

Пример фрагмента кода из моего контроллера:

[HttpGet]
[ResponseCache(Duration = 60)]
public ActionResult<SomeTyp[]> SendDtos()
{
    var dtos = _repository.QueryAll();

    return Ok(dtos);
}

1 Ответ

0 голосов
/ 23 ноября 2018

Существует решение с использованием заголовков 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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...