How to Cancel the Annoying Reconnection of Blazor Server?

How to Cancel the Annoying Reconnection of Blazor Server?

Solve this problem using the solution provided by Microsoft

Last updated 6/23/2023 8:26 AM
Token
5 min read
Category
Blazor
Tags
.NET C# Blazor

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 than 5000 (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

Keep Exploring

Related Reading

More Articles
Same category / Same tag 11/6/2024

Why My Blog Website Returned to Blazor

The development of the blog website has gone through many hardships, with nearly 10 versions including MVC, Vue, Go, etc. Now it has returned to Blazor and adopted static SSR, resulting in a significant speed increase and successful launch.

Continue Reading
Same category / Same tag 2/29/2024

Data Display Can Also Be Done Like This in Winform

In the process of developing Winform, data display functionality is often required. Previously, the gridcontrol control was commonly used. Today, through an example, I would like to introduce how to use the table component from Ant Design Blazor for data display in a Winform Blazor Hybrid application.

Continue Reading
Same category / Same tag 2/29/2024

Can the Winform interface also look good?

A few days ago, I introduced using Blazor Hybrid in Winform, and mentioned that with the Blazor UI, our Winform programs can be designed to look better. Next, I will illustrate with an example of drawing in Winform Blazor Hybrid, hoping it helps you.

Continue Reading