Blazor Server Circuit Reconnection and Graceful Degradation for Production
Make Blazor Server survive transient network loss with automatic circuit reconnection, visible reconnect UI, persisted state, and safe fallbacks for permanent disconnects.
06 Aug 2026, 17:45 UTC

Problem: transient network loss kills the Blazor Server UI
On Blazor Server a dropped SignalR connection pauses the circuit. Users see a frozen UI or a generic reconnect spinner, and any component state that lives only in memory is lost when the circuit is finally disposed. The useful takeaway is that automatic reconnection is built in, but you must surface reconnect status, persist critical state outside the circuit, and define a fallback when reconnection fails.
Desired outcome
A Blazor Server app that survives brief network interruptions by automatically reconnecting the SignalR circuit, shows clear reconnect status to the user, and restores component UI from a persisted source without a full page reload. Permanent disconnects fall back to a safe page or manual refresh with diagnostics logged.
Prerequisites
- A .NET 8 or later SDK project using Blazor Server with SignalR hosted on the same app. Transport fallbacks are enabled by default.
- A layout that isolates transient UI state from business state. Critical state should be readable from server session or durable storage.
- Access to modify Program.cs and the shared layout, and permission to write server logs for circuit events.
Configure circuit options and reconnection UI
In Program.cs configure circuit limits and disconnect behavior. Run this in the project root with write access to the source files.
builder.Services.AddServerSideBlazor(options => {
options.DisconnectedCircuitRetentionPeriod = TimeSpan.FromSeconds(30);
options.JSInteropDefaultCallTimeout = TimeSpan.FromSeconds(30);
});
builder.Services.AddSingleton<CircuitHandler>();
Max concurrent circuits and reconnect timeout values are version-sensitive. Do not assume the same defaults across .NET releases.
Add a reconnect display to the main layout so users see status. In Components/Layout/MainLayout.razor place the component near the top of the body.
<div class="app-shell">
<ReconnectionDisplay />
@Body
</div>
Create ReconnectionDisplay.razor using the built-in reconnect UI pattern. This component shows while the circuit is reconnecting and allows manual retry.
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@implements IDisposable
@if (reconnecting) {
<div class="reconnect-overlay">
Reconnecting... <button @onclick="Retry">Retry</button>
</div>
}
Persist state that must survive disconnect
Circuit reconnection does not automatically restore in-memory component fields. Move critical state to a service backed by session or durable storage and reload on OnInitialized.
public class CartState {
public List<Item> Items { get; set; } = new();
public Task SaveAsync(ISession session) { /* serialize */ }
public Task LoadAsync(ISession session) { /* deserialize */ }
}
In a component, load from the service on init and save on relevant changes. Transient UI flags can be rebuilt; business data must be persisted.
Handle circuit handler events for diagnostics
Register a CircuitHandler to log lifecycle transitions. This helps detect reconnection storms and circuit limits.
public class LoggingCircuitHandler : CircuitHandler {
public override Task OnCircuitOpenedAsync(Circuit circuit, CancellationToken ct) {
Log.Information("Circuit opened {Id}", circuit.Id);
return Task.CompletedTask;
}
public override Task OnCircuitClosedAsync(Circuit circuit, CancellationToken ct) {
Log.Information("Circuit closed {Id}", circuit.Id);
return Task.CompletedTask;
}
}
Register the handler as a singleton. Log entries are for diagnostics and alerting, not for user-facing messages.
Validate reconnection behavior
Simulate network interruption in browser dev tools by setting Network to Offline for a few seconds then back to Online. Observe the reconnect overlay appears and the UI resumes without a full reload.
Inspect server logs for circuit opened and closed events. After a successful reconnect the circuit ID changes, which is expected. Confirm components reload state from the persisted source rather than showing empty defaults.
Open multiple tabs to verify circuit isolation and limits. Server resources scale with active circuits, and reconnection storms can increase memory pressure.
Recovery options and limits
If reconnection exceeds the retention period, the circuit is disposed. Provide a manual refresh fallback and a redirect to a prerendered page for permanent disconnect.
- Manual refresh: expose a Retry button that calls NavigationManager.Refresh().
- Permanent disconnect: navigate to a static informational page with a retry link.
- Logging and alerting: emit circuit error events to your observability pipeline for threshold alerts.
Limitations: in-memory component state not persisted before disconnect is lost. Circuit lifetime, max concurrent circuits, and reconnect timeout behavior are version-sensitive. Do not assume automatic state restoration.
Practical check: after a simulated disconnect, verify the UI state matches the persisted source, the reconnect overlay appeared, and server logs show a circuit close followed by a new circuit open.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.