Azure Functions (v3): Response Caching
This article describes how to add response caching to an Azure Functions v3 App. Response […]
This article describes how to add response caching to an Azure Functions v3 App. Response Caching can reduce the number of requests to your Functions significantly which helps you save costs and boosts performance.
In any asp.net core web app we could just add the response cache middleware, use the ResponseCache attribute and we are done. Unfortunately, the current functions runtime does not support running any middleware out of the box, so I decided to mimic the basic behavior of the ResponseCache-Attribute using my own attribute.
Be aware that my implementation has the following consequences:
- You cannot use model binding (which is very limited anyway)
VaryByis not supported- Cache Profiles are not supported (but could be implemented)
- The attribute uses
FunctionInvocationFilterAttributewhich is currently in preview
Required NuGet Packages
Azure Functions Response Caching: The Code
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.Net.Http.Headers;
namespace tebest.Func
public override async Task OnExecutedAsync(
FunctionExecutedContext executedContext,
CancellationToken cancellationToken)
{
if (!(executedContext.Arguments.First().Value is HttpRequest request))
throw new ApplicationException(
"HttpRequest is null. ModelBinding is not supported, " +
"please use HttpRequest as input parameter and deserialize " +
"using helper functions.");
switch (cacheLocation)
{
case ResponseCacheLocation.Any:
headers.CacheControl = new CacheControlHeaderValue()
{
MaxAge = TimeSpan.FromSeconds(_duration),
NoStore = false,
Public = true
};
break;
case ResponseCacheLocation.Client:
headers.CacheControl = new CacheControlHeaderValue()
{
MaxAge = TimeSpan.FromSeconds(_duration),
NoStore = false,
Public = true
};
break;
case ResponseCacheLocation.None:
headers.CacheControl = new CacheControlHeaderValue()
{
MaxAge = TimeSpan.Zero,
NoStore = true
};
break;
default:
throw new ArgumentOutOfRangeException();
}
await base.OnExecutedAsync(executedContext, cancellationToken);
}
}
}
Usage
[FunctionName(nameof(GetCars))]
[FunctionResponseCache(60 * 60, ResponseCacheLocation.Any)]
[ProducesResponseType(typeof(IEnumerable), (int)System.Net.HttpStatusCode.OK)]
public async Task GetCars(
[HttpTrigger(AuthorizationLevel.Function, "get", Route = "v1/cars")]
HttpRequest req,
ILogger log)
{
return await _carService.GetCarList(ps);
}
Notes
In case of an exception, the result will not be cached, despite what is set in the attribute. You should probably fine-tune this to check for appropriate HTTP response status codes, as you may not just throw exceptions in every scenario.
This post was initially published on tebest.net


