Implementing .NET Core API Caching in C#

By FoxLearn 1/10/2025 2:34:59 AM   62
To implement caching in a .NET Core API using AddResponseCaching and the [ResponseCache] attribute, follow these steps.

Caching an API response can significantly improve the performance of your API by avoiding the need to regenerate the response each time. Instead, the response is retrieved from memory, making it especially beneficial for API endpoints with expensive or time-consuming computations that return the same results repeatedly.

Enable Caching in Program.cs

First, ensure that caching is enabled globally in your application by adding AddResponseCaching and UseResponseCaching in your Program.cs file:

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddResponseCaching();  // Add response caching service

var app = builder.Build();

// Configure the HTTP request pipeline.
app.UseHttpsRedirection();

// UseResponseCaching should be called after any other middleware such as UseCors
app.UseResponseCaching();  // Enable response caching middleware

app.UseAuthorization();
app.MapControllers();

app.Run();

Make sure UseResponseCaching is called after UseCors (if CORS is enabled).

In the code above:

  • AddResponseCaching() registers the necessary services to support response caching.
  • UseResponseCaching() middleware is added to the request pipeline.

Use the [ResponseCache] Attribute in Controllers

Next, you need to specify caching behavior for each API endpoint using the [ResponseCache] attribute.

The [ResponseCache] attribute allows you to control the caching parameters for an individual action. You can specify the duration for which the response should be cached and configure other settings like how the cache should vary based on query parameters or headers.

using Microsoft.AspNetCore.Mvc;

namespace MyApi.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class CatFactsController : ControllerBase
    {
        [HttpGet]
        [ResponseCache(Duration = 10)]  // Cache the response for 10 seconds
        public string GetCatFact()
        {
            // Simulate fetching a random cat fact
            var catFact = "Cats have five toes on their front paws, but only four toes on their back paws.";
            return catFact;
        }
    }
}

In the example above, the GetCatFact action is cached for 10 seconds. When the same request is made within that time, the response will be fetched from the cache rather than executing the logic again.

Vary Cache Based on Query Parameters or Headers

You can vary the cache based on query parameters or headers using VaryByQueryKeys or VaryByHeader.

[HttpGet]
[ResponseCache(Duration = 30, VaryByQueryKeys = new[] { "id", "search" })]  // Cache based on query parameters
public string GetCatFact([FromQuery] int id, [FromQuery] string search)
{
    // Simulate fetching a random cat fact, with a variation based on 'id' and 'search' query parameters
    var catFact = $"Cat Fact for {id} with search term '{search}'";
    return catFact;
}

In this example, the cache is varied by the id and search query parameters, meaning different combinations of these parameters will result in different cached responses.

Define Cache Profiles for Reusability

Instead of specifying caching settings directly on each controller action, you can define cache profiles in Program.cs or Startup.cs and apply them globally or to specific actions.

For example, you can define a cache profile for default caching behavior:

builder.Services.AddControllers(options =>
{
    options.CacheProfiles.Add("Default", new CacheProfile() { Duration = 10 });
    options.CacheProfiles.Add("Client", new CacheProfile() { Location = ResponseCacheLocation.Client, Duration = 10 });
});

Then, use the CacheProfileName property of the [ResponseCache] attribute:

[HttpGet]
[ResponseCache(CacheProfileName = "DefaultCache")]
public string GetCatFact()
{
    var catFact = "Cats love to sleep for 12-16 hours a day.";
    return catFact;
}

[HttpGet("2")]
[ResponseCache(CacheProfileName = "Client", VaryByQueryKeys = new[] { "id", "search" })]  // Use the "Client" profile with query parameter variation
public string? GetCatFact2([FromQuery] int id, [FromQuery] string search)
{
  CatModel? catFact = _httpRepository.GetAsync<CatModel>("https://catfact.ninja/fact").Result;
  return catFact?.Fact + id + search;
}

By implementing response caching, you can speed up your API by storing frequently accessed data in memory, reducing the need to reprocess the same requests. You can fine-tune caching based on query parameters, headers, or reusable cache profiles for optimal performance.