ResponseCacheAttribute
is part of MVC and as per docs will be applied to:
- Razor Pages: Attributes can't be applied to handler methods.
- MVC controllers.
- MVC action methods: Method-level attributes override the settings specified in class-level attributes.
So it seems that adding cache header yourself is an only option. If you want you can "prettify" it a little bit using custom middleware. Something along this lines:
class CacheResponseMetadata
{
// add configuration properties if needed
}
class AddCacheHeadersMiddleware
{
private readonly RequestDelegate _next;
public AddCacheHeadersMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext httpContext)
{
if (httpContext.GetEndpoint()?.Metadata.GetMetadata<CacheResponseMetadata>() is { } mutateResponseMetadata)
{
if (httpContext.Response.HasStarted)
{
throw new InvalidOperationException("Can't mutate response after headers have been sent to client.");
}
httpContext.Response.Headers.CacheControl = new[] { "public", "max-age=100" };
}
await _next(httpContext);
}
}
And usage:
app.UseMiddleware<AddCacheHeadersMiddleware>(); // optionally move to extension method
app.MapGet("/cache", () => $"Hello World, {Guid.NewGuid()}!")
.WithMetadata(new CacheResponseMetadata()); // optionally move to extension method
.NET 7 update
For .NET 7 you can configure output caching (see the linked article for differences with response caching):
The output caching middleware can be used in all types of ASP.NET Core apps: Minimal API, Web API with controllers, MVC, and Razor Pages.
Output caching can be done per endpoint via OutputCacheAttribute
or CacheOutput
method call:
app.MapGet("/cached", Gravatar.WriteGravatar).CacheOutput();
app.MapGet("/attribute", [OutputCache] (context) => Gravatar.WriteGravatar(context));
Or for multiple endpoints via policy:
The following code configures caching for all of the app's endpoints, with expiration time of 10 seconds.
builder.Services.AddOutputCache(options =>
{
options.AddBasePolicy(builder => builder.Expire(TimeSpan.FromSeconds(10)));
});