From ffba74a7277a892abed0737eb0ba2992aa5d406f Mon Sep 17 00:00:00 2001 From: "soroush.asadi" Date: Fri, 26 Jun 2026 11:03:37 +0330 Subject: [PATCH] Cache-busting so deploys are visible immediately The site sits behind a CDN and shipped static assets with no Cache-Control and no versioning, so browsers/CDN kept serving stale css/js after a deploy (the "design didn't change" symptom). - HTML responses now send Cache-Control: no-cache, no-store, must-revalidate so the page itself is always revalidated. - Static assets get a long cache and are fingerprinted via asp-append-version (/css/site.css?v=), so they bust automatically on every change. Co-Authored-By: Claude Opus 4.8 --- Pages/Shared/_AdminLayout.cshtml | 4 ++-- Pages/Shared/_Layout.cshtml | 8 ++++---- Program.cs | 24 +++++++++++++++++++++++- 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/Pages/Shared/_AdminLayout.cshtml b/Pages/Shared/_AdminLayout.cshtml index 5516c94..60b6047 100644 --- a/Pages/Shared/_AdminLayout.cshtml +++ b/Pages/Shared/_AdminLayout.cshtml @@ -9,8 +9,8 @@ @@font-face { font-family:'SpaceMono'; src:url('/fonts/SpaceMono-Regular.woff2') format('woff2'); font-display:swap; } - - + +
diff --git a/Pages/Shared/_Layout.cshtml b/Pages/Shared/_Layout.cshtml index 919ce4e..d8130ab 100644 --- a/Pages/Shared/_Layout.cshtml +++ b/Pages/Shared/_Layout.cshtml @@ -26,9 +26,9 @@ - - - + + + @@ -155,7 +155,7 @@
- + @await RenderSectionAsync("Scripts", required: false) diff --git a/Program.cs b/Program.cs index cce72c3..23a8b91 100644 --- a/Program.cs +++ b/Program.cs @@ -50,7 +50,29 @@ using (var scope = app.Services.CreateScope()) } app.UseStatusCodePagesWithReExecute("/Error/{0}"); -app.UseStaticFiles(); + +// HTML pages must never be cached by the browser or CDN, so a new deploy is +// visible immediately. Static assets are fingerprinted via asp-append-version +// (?v=hash), so they can be cached aggressively and bust automatically. +app.Use(async (context, next) => +{ + context.Response.OnStarting(() => + { + if (context.Response.ContentType?.Contains("text/html", StringComparison.OrdinalIgnoreCase) == true) + { + context.Response.Headers.CacheControl = "no-cache, no-store, must-revalidate"; + context.Response.Headers.Pragma = "no-cache"; + } + return Task.CompletedTask; + }); + await next(); +}); + +app.UseStaticFiles(new StaticFileOptions +{ + OnPrepareResponse = ctx => + ctx.Context.Response.Headers.CacheControl = "public, max-age=31536000" +}); // Serve uploaded files from /data/uploads under /uploads/* var uploadsPath = Path.Combine(dataDir, "uploads");