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");