Which cache-busting strategy reliably recovers a Blazor WebAssembly app from a failed deployment?
0 reputation · 04 Jul 2024, 12:47 UTC
0 reputation · 04 Jul 2024, 12:47 UTC
I'm planning the rollback and recovery story for a Blazor WebAssembly application (targeting .NET 8) where a failed or partial upgrade can leave the browser holding stale framework and application assemblies. The goal is to let the client recover on its own after a corrected redeploy, without asking users to clear their browser cache manually.
My understanding is that the default project template does not ship with a standardized version-invalidation mechanism, so developers typically add query-string cache-busting, customize the service worker (for published PWA assets), or implement their own NavigationManager logic to force a reload when a version mismatch is detected. I'm unsure which of these is dependable across browsers, since private/incognito modes and aggressive HTTP caching can retain old .dll files even after a hard refresh.
On the Blazor Server side, I also assume a circuit that disconnects mid-upgrade cannot resynchronize state across version boundaries, so recovery there effectively means a client reconnect and possibly a host restart, with in-memory circuit state lost. Is that assumption correct for .NET 8's reconnection heuristics?
Specifically: which documented mechanism (service worker update flow, assembly version check plus forced reload, or something else) is the most reliable trigger for discarding stale assemblies? Can the client detect a version mismatch itself, or must the server signal it? And how should this be verified in the Network tab beyond checking the requested .dll versions?
31775 reputation · 04 Jul 2024, 15:21 UTC
The most reliable recovery trigger is a server-published version token that the client polls and compares, followed by a full page reload on mismatch. Query-string cache busting alone is not dependable, and the PWA service worker update flow is reliable only if you actually ship a PWA. The version-check pattern works in every hosting model, including plain static hosting behind a CDN.
Query-string busting (app.dll?v=1.2.3) only helps if the HTML or boot manifest that references the DLL is itself re-fetched. With aggressive headers like Cache-Control: immutable on _framework/*, or in private browsing sessions with odd cache partitioning, the browser can keep serving the old boot JSON and old DLLs regardless of your query string. The service worker flow (registration update, activate, reload) is solid, but only exists in PWA builds — a standard Blazor WASM deployment has no service worker at all.
version.json containing a build hash or timestamp works, or reuse blazor.boot.json, which already changes on every build.Cache-Control: no-store so the client always reads the live value.sessionStorage or captured at boot.NavigationManager.NavigateTo(uri, forceLoad: true) or location.reload(). The reload re-fetches the boot manifest and all assemblies fresh.The client can detect the mismatch entirely on its own — no server push is required. The server only needs to publish the new token as part of the deploy.
Yes, that's essentially correct for .NET 8. A circuit holds in-memory state tied to the server process and assembly set. If the server is redeployed mid-circuit, the reconnection handshake fails and the client falls back to its reconnection UI, ultimately requiring a full reload; circuit state is lost. There is no cross-version circuit resync. So the same version-check-plus-reload pattern gives you a consistent recovery story on both hosting models.
Beyond checking DLL URLs, verify these:
200 with no-store and is never served from disk cache or the service worker.blazor.boot.json and .dll requests show fresh responses — status 200, not "(from ServiceWorker)" or "(disk cache)".If you're behind a CDN, confirm it doesn't cache your version endpoint or strip query strings. And persist unsaved user input before forcing the reload — recovery shouldn't destroy user data. One open detail that could change this recommendation: if your app is already published as a PWA, the built-in service worker update flow may be sufficient on its own, and you'd only need the version check as a belt-and-braces trigger.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.