This article is a repost.
Original Author: Token
Original Title: How to Cancel the Annoying Reconnection UI in Blazor Server?
Original Link: https://www.cnblogs.com/hejiale010426/p/17498629.html
Many Blazor users tend to choose the faster-loading Blazor Server mode when developing internal systems.
However, since Blazor Server is implemented via SignalR, it establishes a WebSocket channel during access for JS interaction and UI rendering. Because WebSocket is a persistent connection, it stays connected when the user is on the page, consuming server bandwidth. Therefore, Microsoft automatically disconnects when there is no activity and adds a rather unattractive reconnection UI—a gray overlay that many users find unpleasing. Of course, Microsoft also provides a way to handle this situation. Below, we will use Microsoft’s solution to address this issue.
Create an Empty Blazor Server Project
Below is the newly created empty Blazor Server project.

Then, after leaving it idle for a while, the following situation appears.

That ugly loading UI with a full gray overlay needs to be removed.
Remove the Gray Loading Style
Add a boot.js script to handle reconnection.
boot.js is used to customize reconnection behavior and take over the reconnection process.
(() => {
// Maximum retry count
const maximumRetryCount = 10000;
// Retry interval
const retryIntervalMilliseconds = 1000;
const startReconnectionProcess = () => {
let isCanceled = false;
(async () => {
for (let i = 0; i < maximumRetryCount; i++) {
console.log(`Attempting reconnection: ${i + 1} of ${maximumRetryCount}`);
await new Promise((resolve) =>
setTimeout(resolve, retryIntervalMilliseconds)
);
if (isCanceled) {
return;
}
try {
const result = await Blazor.reconnect();
if (!result) {
// Reached the server but connection was rejected; reload the page.
location.reload();
return;
}
// Successfully reconnected to the server.
return;
} catch {
// Did not reach the server; try again.
}
}
// Too many retries; reload the page.
location.reload();
})();
return {
cancel: () => {
isCanceled = true;
},
};
};
let currentReconnectionProcess = null;
Blazor.start({
configureSignalR: function (builder) {
let c = builder.build();
c.serverTimeoutInMilliseconds = 30000;
c.keepAliveIntervalInMilliseconds = 15000;
builder.build = () => {
return c;
};
},
reconnectionHandler: {
onConnectionDown: () =>
(currentReconnectionProcess ??= startReconnectionProcess()),
onConnectionUp: () => {
currentReconnectionProcess?.cancel();
currentReconnectionProcess = null;
},
},
});
})();
Modify Pages/_Host.cshtml:
@page "/" @using Microsoft.AspNetCore.Components.Web @namespace BlazorApp1.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<base href="~/" />
<link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" />
<link href="css/site.css" rel="stylesheet" />
<link href="BlazorApp1.styles.css" rel="stylesheet" />
<link rel="icon" type="image/png" href="favicon.png" />
<component type="typeof(HeadOutlet)" render-mode="ServerPrerendered" />
</head>
<body>
<component type="typeof(App)" render-mode="ServerPrerendered" />
<div id="blazor-error-ui">
<environment include="Staging,Production">
An error has occurred. This application may no longer respond until reloaded.
</environment>
<environment include="Development">
An unhandled exception has occurred. See browser dev tools for details.
</environment>
<a href="" class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>
<script src="_framework/blazor.server.js" autostart="false"></script>
<script src="/boot.js"></script>
</body>
</html>
We have modified the reference to blazor.server.js.
Changed from <script src="_framework/blazor.server.js"></script> to <script src="_framework/blazor.server.js" autostart="false"></script>
Let me explain why we made this change: we need to customize the handler, but referencing blazor.server.js directly would cause it to execute immediately without waiting for our handler. Therefore, we add autostart="false" to prevent the default startup.
Then, we customize the startup process in the script below. We have also added the reference <script src="/boot.js"></script> above, and the custom handler below will start the Blazor Server application.
<script>
Blazor.start({
configureSignalR: function (builder) {
let c = builder.build();
c.serverTimeoutInMilliseconds = 30000;
c.keepAliveIntervalInMilliseconds = 15000;
builder.build = () => {
return c;
};
}
});
</script>
serverTimeoutInMilliseconds: Server timeout in milliseconds. If this timeout elapses without receiving any message from the server, the connection will be terminated with an error. The default timeout is 30 seconds. The server timeout should be at least double the value assigned to the Keep-Alive interval (keepAliveIntervalInMilliseconds).keepAliveIntervalInMilliseconds: The default interval at which to ping the server. With this setting, the server can detect forcefully disconnected situations, such as when a client disconnects from its network. This ping occurs at most as frequently as the server pings. If the server pings every 5 seconds, a value lower than5000(5 seconds) will still result in a ping every 5 seconds. The default is 15 seconds. The Keep-Alive interval should be less than or equal to half the value assigned to the server timeout (serverTimeoutInMilliseconds).
After writing this, start the application and then shut down the backend service. Our interface no longer displays the above UI.

When the backend starts again, it will automatically reconnect to the frontend without any impact on the UI.
Conclusion
Shared by Token
Blazor Technical Exchange Group: 452761192