如何取消Blazor Server煩人的重新連線?

如何取消Blazor Server煩人的重新連線?

使用微軟提供的方案解決這個問題

最後更新 2023/6/23 上午8:26
Token
預計閱讀 5 分鐘
分類
Blazor
標籤
.NET C# Blazor

本文來自轉載

原文作者:Token

原文標題:如何取消 Blazor Server 煩人的重新連線?

原文連結:https://www.cnblogs.com/hejiale010426/p/17498629.html

相信很多 Blazor 的使用者在開發內部系統時基本上都選擇速度更快、載入更快的 Blazor Server 模式。

但是 Blazor Server 因為是 SignalR 實作,所以在存取時會建立 WebSocket 通道,用於 js 互動和介面渲染,但由於 WebSocket 是長連線,這樣就會導致使用者在介面時會一直建立連線,造成伺服器頻寬佔用,所以微軟預設會在無操作的情況下自動斷開連線,然後會加上那個惱人的重新連線 UI,很難看,導致很多使用者看到灰色的效果。當然,微軟也提供了處理這種情況的方案,下面我們會使用微軟提供的方案解決這個問題。

建立 Blazor Server 的空專案

下面是剛建立的 Blazor Server 空專案。

然後長時間掛著就會出現下面這種情況。

很醜的載入 UI,灰色的全面覆蓋樣式,下面就必須解決這個問題。

移除灰色載入樣式

新增 boot.js JS 腳本,用來處理重新連線。

boot.js 用於自訂重新連線的操作,並接管重新連線的程序。

(() => {
  // 重試次數
  const maximumRetryCount = 10000;

  // 重試間隔
  const retryIntervalMilliseconds = 1000;

  const startReconnectionProcess = () => {
    let isCanceled = false;

    (async () => {
      for (let i = 0; i < maximumRetryCount; i++) {
        console.log(`試圖重新連線: ${i + 1} of ${maximumRetryCount}`);
        await new Promise((resolve) =>
          setTimeout(resolve, retryIntervalMilliseconds)
        );

        if (isCanceled) {
          return;
        }

        try {
          const result = await Blazor.reconnect();
          if (!result) {
            // 已到達伺服器,但連線被拒絕;重新載入頁面。
            location.reload();
            return;
          }

          // 成功重新連線到伺服器。
          return;
        } catch {
          // 沒有到達伺服器;再試一次。
        }
      }

      // 重試次數過多;重新載入頁面。
      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;
      },
    },
  });
})();

修改 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">
        發生錯誤。此應用程式在重新載入之前可能不再回應。
      </environment>
      <environment include="Development">
        發生了一個未處理的例外。詳細資訊請參見瀏覽器開發工具。
      </environment>
      <a href="" class="reload">重新載入</a>
      <a class="dismiss">🗙</a>
    </div>

    <script src="_framework/blazor.server.js" autostart="false"></script>
    <script src="/boot.js"></script>
  </body>
</html>

我們修改了 blazor.server.js 的引用。

<script src="_framework/blazor.server.js"></script> 改成 <script src="_framework/blazor.server.js" autostart="false"></script>

說明一下為什麼要改這個。我們需要自訂處理程式,但引用了 blazor.server.js,它就會直接執行,並不會等我們的處理程式,所以需要加上 autostart="false" 阻止預設的啟動程式。

然後在下面的腳本中自訂啟動程式,在上面還引用了 <script src="/boot.js"></script>,然後下面的自訂處理啟動 Blazor Server 程式。

   <script>
        Blazor.start({
            configureSignalR: function (builder) {
                let c = builder.build();
                c.serverTimeoutInMilliseconds = 30000;
                c.keepAliveIntervalInMilliseconds = 15000;
                builder.build = () => {
                    return c;
                };
            }
        });
    </script>
  • serverTimeoutInMilliseconds:伺服器逾時(以毫秒為單位)。 如果此逾時已過但未從伺服器接收任何訊息,連線將終止並出現錯誤。 預設逾時值為 30 秒。 伺服器逾時應至少是分配給 Keep-Alive 間隔 (keepAliveIntervalInMilliseconds) 的值的兩倍。
  • keepAliveIntervalInMilliseconds:ping 伺服器時採用的預設間隔。 使用此設定,伺服器可以偵測強行斷開連線的情況,例如用戶端中斷其電腦的網路連線。 此 ping 的發生頻率最多與伺服器 ping 的頻率一樣。 如果伺服器每 5 秒 ping 一次,則分配的值低於 5000(5 秒)時,將會每 5 秒 ping 一次。 預設值為 15 秒。 Keep-Alive 間隔應小於或等於分配給伺服器逾時 (serverTimeoutInMilliseconds) 的值的一半。

寫完以後啟動程式,然後將後端服務關閉,然後我們的介面並未再出現上面的 UI 了。

當我們的後端啟動就會與前端自動連線,並且不會對前端造成影響。

結尾

來自 token 的分享

Blazor 技術交流群:452761192

繼續探索

延伸閱讀

更多文章
同分類 / 同標籤 2024/2/29

Winform中也可以這樣做資料展示

在做winform開發的過程中,經常需要做資料展示的功能,之前一直使用的是gridcontrol控制項,今天想透過一個範例,跟大家介紹一下如何在winform blazor hybrid中使用ant design blazor中的table元件做資料展示。

繼續閱讀
同分類 / 同標籤 2024/2/29

Winform的介面也可以變好看?

前幾天跟大家介紹了在winform中使用blazor hybrid,而且還說配上blazor的UI可以讓我們的winform程式設計的更加好看,接下來我想以一個在winform blazor hybrid中繪圖的範例來進行說明,希望對你有所幫助。

繼續閱讀