Finally! Improved Blazor Server reconnection UX
Caution!
If you’ve built web apps with Blazor Server the following may cause distress! 😅
Attempting to reconnect to the server…
Reconnection failed. Try reloading the page if you’re unable to reconnect.
These are the standard Blazor error messages your users have likely complained about as they interact with your Blazor application.
These errors occur because of the connected nature of Blazor server apps.
A circuit runs on the server (for a given user interaction), and a SignalR (websocket) connection is maintained between the user’s browser and said circuit.
Unfortunately this can mean your users end up being forcing to click a ‘Reload’ hyperlink to refresh the app, causing them to lose any unsaved work in the process.
Improved error handling in .NET 9
.NET 9 brings improvements in this area.
First up, there’s a nicer default UI which is shown if connection is lost.
You can’t see it here, but the blue circles are animated, and the timer counts down until a connection retry is attempted.
In addition to the changed default UI, Blazor will now attempt to reconnect to the server using an exponential backoff strategy.
In effect, this means it will try to reconnect a few times in quick succession, before gradually increasing the delay between retries.
Furthermore, if a user navigates to an app with a disconnected circuit (for example, because they open a tab for your app after being away from it for a time) Blazor will attempt to reconnect immediately.
In many cases this will seamlessly bring the disconnected app back to life.
But if Blazor can’t reconnect to the original cricuit it will refresh the entire page automatically.
Tweak the configuration
While Blazor ships with standard logic, including how often to retry the connection, you can tweak this for your specific purposes.
The trick is to override how Blazor starts.
First by disabling autostart
in your app.razor component.
<script src="_framework/blazor.web.js" autostart="false"></script>
Then by manually starting Blazor, passing your own configuration for the circuit reconnection logic.
<script>
Blazor.start({
circuit: {
reconnectionOptions: {
maxRetries: 6,
retryIntervalMilliseconds: (previousAttempts, maxRetries) =>
previousAttempts >= maxRetries
? null
: previousAttempts * 1000
},
},
});
</script>
This indicates we want to attempt reconnection 6 times, with the delay between each attempt increasing by 1 second (1000 milliseconds) for every attempt.
Finally, when previousAttempts hits (or exceeds) our value for max retries (6) we return null which halts the reconnection logic.
You can also just pass an array of millisecond values if you prefer.
<script>
Blazor.start({
circuit: {
reconnectionOptions: {
retryIntervalMilliseconds:
Array.prototype.at.bind(
[0, 1000, 2000, 5000, 10000, 15000, 30000, 60000]
),
},
},
});
</script>
Here, retries will stop after the last specified retry interval (when the function returns undefined).
In summary
If you’re building a Blazor Server app (or an app with some interactivity using Blazor server) .NET 9 improves the default experience for handling server disconnects.
The ‘out of the box’ defaults work well in most cases but, should you need to, you can also configure the retry logic for your specific app.
– Jon