Disable HTTP caching by default in ASP.NET Core APIs

 
 
  • Gérald Barré

When building APIs with ASP.NET Core, it's crucial to explicitly control caching behavior. Unlike web pages where caching often improves user experience, API responses should not be cached by default unless you intentionally design them to be cacheable. Unintended caching can lead to serious issues, including stale data, security vulnerabilities, and hard-to-reproduce bugs.

#Understanding HTTP caching standards

HTTP caching is governed by RFC 7234 (HTTP/1.1 Caching) and RFC 9111 (HTTP Caching). According to these specifications, caches may store responses and serve them without contacting the origin server, using headers like Cache-Control, Expires, ETag, and Last-Modified.

When cache headers are absent, caches might apply heuristic expiration, caching your API responses even without explicit directives. This is particularly problematic because browsers and intermediate caches (such as CDNs, proxies, or gateway caches) may use their own algorithms to decide how long to store a response.

#Implementing a no-cache middleware

To ensure API responses are not cached by default, implement a middleware that sets the appropriate cache control headers. It adds the necessary headers to prevent caching unless you explicitly override them in specific controllers or actions.

Here's how to create such a middleware:

C#
internal sealed class NoCacheMiddleware(RequestDelegate next)
{
    public async Task InvokeAsync(HttpContext context)
    {
        context.Response.OnStarting(() =>
        {
            // Only set no-cache headers if they are not already explicitly set
            if (context.Response.Headers.CacheControl.Count is 0)
            {
                context.Response.Headers.CacheControl = "no-cache,no-store,must-revalidate";
            }

            return Task.CompletedTask;
        });

        await next(context);
    }
}

Register the middleware in your ASP.NET Core pipeline:

C#
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseMiddleware<NoCacheMiddleware>();
app.MapGet("/", () => "Hello World!");
app.Run();

#Additional resources

Do you have a question or a suggestion about this post? Contact me!

Follow me:
Enjoy this blog?