Как в ASP.NET WebAPI настроить кэширование ответов на HTTP-запросы?csharp-75

Основные подходы к кэшированию

В ASP.NET WebAPI существует несколько способов реализации кэширования HTTP-ответов:

  1. Кэширование на стороне сервера
  2. Кэширование на стороне клиента
  3. Гибридное кэширование

1. Кэширование на стороне сервера

OutputCache

[OutputCache(Duration = 60)] // Кэшировать на 60 секунд
public HttpResponseMessage Get(int id)
{
    var product = _repository.GetProduct(id);
    return Request.CreateResponse(HttpStatusCode.OK, product);
}

Использование MemoryCache

private static MemoryCache _cache = new MemoryCache(new MemoryCacheOptions());

public IHttpActionResult Get(string key)
{
    if (_cache.TryGetValue(key, out var cachedData))
    {
        return Ok(cachedData);
    }

    var data = GetExpensiveData();
    _cache.Set(key, data, TimeSpan.FromMinutes(10));
    return Ok(data);
}

2. Кэширование на стороне клиента

Cache-Control заголовки

public HttpResponseMessage Get()
{
    var response = Request.CreateResponse(HttpStatusCode.OK, GetData());
    response.Headers.CacheControl = new CacheControlHeaderValue
    {
        MaxAge = TimeSpan.FromSeconds(3600),
        MustRevalidate = true,
        Public = true
    };
    return response;
}

ETag для валидации кэша

public HttpResponseMessage Get(int id)
{
    var product = _repository.GetProduct(id);
    var etag = $"\"{product.Version}\""; // Уникальный идентификатор версии

    if (Request.Headers.IfNoneMatch.Any(h => h.Tag == etag))
    {
        return Request.CreateResponse(HttpStatusCode.NotModified);
    }

    var response = Request.CreateResponse(HttpStatusCode.OK, product);
    response.Headers.ETag = new EntityTagHeaderValue(etag);
    return response;
}

3. Распределенное кэширование

IDistributedCache

public class ProductsController : ApiController
{
    private readonly IDistributedCache _cache;

    public ProductsController(IDistributedCache cache)
    {
        _cache = cache;
    }

    public async Task<IHttpActionResult> Get(int id)
    {
        var cacheKey = $"product_{id}";
        var cachedProduct = await _cache.GetStringAsync(cacheKey);

        if (cachedProduct != null)
        {
            return Ok(JsonConvert.DeserializeObject<Product>(cachedProduct));
        }

        var product = _repository.GetProduct(id);
        await _cache.SetStringAsync(cacheKey,
            JsonConvert.SerializeObject(product),
            new DistributedCacheEntryOptions
            {
                AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30)
            });

        return Ok(product);
    }
}

4. Атрибут ResponseCache

Для ASP.NET Core WebAPI:

[ResponseCache(Duration = 60, Location = ResponseCacheLocation.Client)]
[HttpGet("{id}")]
public ActionResult<Product> GetById(int id)
{
    return _repository.GetProduct(id);
}

Продвинутые сценарии

Кастомный ActionFilter для кэширования

public class CacheAttribute : ActionFilterAttribute
{
    public int Duration { get; set; }

    public override void OnActionExecuted(HttpActionExecutedContext context)
    {
        if (context.Response != null)
        {
            context.Response.Headers.CacheControl = new CacheControlHeaderValue
            {
                MaxAge = TimeSpan.FromSeconds(Duration),
                MustRevalidate = true,
                Public = true
            };
        }
    }
}

// Использование:
[Cache(Duration = 3600)]
public IHttpActionResult Get() { ... }

Кэширование с зависимостями

public class ProductsController : ApiController
{
    [OutputCache(Duration = 3600, VaryByParam = "category")]
    public HttpResponseMessage GetByCategory(string category)
    {
        // ...
    }
}

Лучшие практики

  1. Для статичных данных используйте длительное кэширование
  2. Для динамических данных - короткое кэширование с валидацией (ETag)
  3. Избегайте кэширования персональных данных
  4. Для распределенных систем используйте IDistributedCache
  5. Учитывайте размер кэшируемых данных

Резюмируем:


В ASP.NET WebAPI доступны различные механизмы кэширования - от простых атрибутов OutputCache до сложных распределенных систем. Выбор подхода зависит от требований приложения: для простых сценариев достаточно серверного кэширования, для сложных распределенных систем лучше использовать IDistributedCache с настройкой соответствующих заголовков HTTP для клиентского кэширования.