Caching whole API response in ASP.NET Core

Caching data with distributed caches like Azure Redis Cache is easy – but how to easily cache whole response from your Web API (response code+body) describes this post.

Following method implements REST Get method in Web API controller Order. This method provides information about order from database:


// GET: order/{orderId}
/// 
/// Get manifest file
/// 
/// Order ID
[HttpGet("order/{orderId}"]
public IActionResult Get(int orderId)
{
    var entry = _repository.GetById(orderId);

    if (entry == null)
        return NotFound("Order not found.");

    return Ok(entry);
}

I needed to add response cache, but I didn’t wanted to care about status codes – if i would only cache the output text, I would miss in cached responses alternative codes like 404 – or i would have to save also some another metadata – which is not so developer-friendly solution.

I got idea – what about cache whole response? Response is object implementing IActionResult, so what about serializate whole response, save to cache – and when is accessed already cached, only load from cache and deserializate and send to client. And how to do it really developer-friendly? I have idea to wrap it into lambda, so original content of method is invoked in lambda and result of the lambda is saved to cache:


// GET: order/{orderId}
/// <summary>
/// Get manifest file
/// </summary>
/// <param name="orderId">Order ID</param>
[HttpGet("order/{orderId}"]
public IActionResult Get(int orderId)
{
    var cacheKey = "Get-Order-" + orderId;
    
    var cachedResponse = _distributedCache.GetString(cacheKey);
    if (!string.IsNullOrEmpty(cachedResponse))
    {
        return JsonConvert.DeserializeObject(cachedResponse);
    }
    }

    Func createResponse = () =>
    {
        var entry = _repository.GetById(orderId);

        if (entry == null)
            return NotFound("Order not found.");

        return Ok(entry);
    };

    var actionResponse = createResponse();
    var serializatedResponse = JsonConvert.SerializeObject(actionResponse);
        _distributedCache.SetString(cacheKey, serializatedResponse);

    return actionResponse;
}