Architecture Note: Blazor Interactive Auto for Progressive Enhancement
Explains how Blazor Interactive Auto provides progressive enhancement, the minimal design, trust boundary shift, operational checks, failure modes, and when to choose a different render mode.
23 Jul 2026, 22:59 UTC

Requirements
Blazor Interactive Auto (@rendermode InteractiveAuto) is chosen when an application needs fast initial paint and SEO‑friendly server rendering, followed by a seamless transition to client‑side execution once the WebAssembly (WASM) bundle is available. The design must satisfy:
- First paint served from the server without waiting for the WASM download.
- Automatic switch to Interactive WebAssembly after the background download finishes.
- Preservation of component state across the switch.
- Clear trust boundary: server‑side code retains full server privileges; after the switch only exposed APIs (HttpClient, SignalR) are reachable from the client.
Smallest Suitable Design
The minimal setup is a single Blazor Web App solution (.NET 8+) that references both the server and client projects. No separate Server‑only or WASM‑only projects are required. Apply @rendermode InteractiveAuto to the root component or any page that should start on the server and later run client‑side.
Example configuration
@page "/counter"
@rendermode InteractiveAuto
@code {
// No additional code needed; the mode is set by the directive.
}
The directive tells the framework to render the component using Interactive Server first, then download the WASM bundle and switch to Interactive WebAssembly when ready.
Trust/Data Boundary
During the server phase the component runs with the same privileges as the ASP.NET Core host (database access, configuration secrets, file system). After the switch, the component executes in the browser sandbox; only data that is explicitly sent over HttpClient or SignalR is available. Therefore:
- Design services as scoped on the server and inject them via
HttpClient(or a typed client) on the client side. - Do not place secret‑dependent logic in component parameters that will be serialized to the client.
- Authentication state (ClaimsPrincipal) flows automatically, but roles or claims must be re‑validated on the client via API calls; client‑side authorization alone is insufficient.
Operational Checks
To verify the progressive‑enhancement behavior in production or staging:
- Monitor
CircuitConnectedandCircuitDisconnectedevents on theHubConnection(SignalR) to know when the server phase is active or lost. - Track the WASM download lifecycle: use
NavigationManager.LocationChangedor a custom JS interop that fires onwasm-download-startandwasm-download-completeevents (these can be emitted viawindow.dispatchEventin a small script). - Check the size of the serialized component state. SignalR’s default message limit is ~32 KB; if the state exceeds this, the switch will fail. Measure by enabling
Microsoft.AspNetCore.SignalRlogging and looking for "Message too large" warnings.
Failure Modes
- Circuit loss before WASM ready: The user sees the built‑in reconnect UI. If circuit state is not persisted (e.g., via
ProtectedBrowserStorage), component state resets after reconnect. - WASM download fails (network or CDN error): The app remains on Interactive Server indefinitely, continuing to consume server resources for each connected client.
- Serialization mismatch: If the server and client are built from different versions of the component or its dependencies, deserialization throws an exception on switch, causing the component to error out.
Conditions That Change the Design
- Strict offline requirement: Choose Interactive WebAssembly only (@rendermode InteractiveWebAssembly) because the server phase cannot be relied upon.
- High server scale with low‑end clients: Stay with Interactive Server (@rendermode InteractiveServer) to avoid sending large WASM bundles to incapable devices.
- Heavy client‑side compute (crypto, ML, image processing): Force WebAssembly via @rendermode InteractiveWebAssembly to avoid round‑trips and to keep sensitive algorithms off the server.
- SEO‑critical pages with no interactivity: Use Static SSR (@rendermode StaticServer) for maximum crawler friendliness and zero client payload.
Verification Steps (non‑exhaustive)
- Create a minimal Blazor Web App (.NET 8+). Add a Counter component with
@rendermode InteractiveAuto. - Open DevTools → Network. Reload the page: observe the initial HTML response, a SignalR negotiation, then a request for
dotnet.wasmand related files. - After the WASM request completes, note the WebSocket used for SignalR closes and a new client‑side circuit is established.
- Add a large state field (e.g.,
List<string> Items = Enumerable.Range(0,5000).Select(i => i.ToString()).ToList()) to the component. Reload and verify the switch fails with a SignalR "Message too large" log. Replace the list with aVirtualizecomponent and confirm the switch succeeds. - Simulate a network failure during the WASM download (DevTools → Offline). Confirm the app stays functional on the server and shows the reconnect UI if the circuit drops.
These steps provide observable evidence without claiming any specific measured outcome.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.