Blazor Serverの煩わしい再接続をキャンセルする方法は?

Blazor Serverの煩わしい再接続をキャンセルする方法は?

Microsoftが提供するソリューションを使用してこの問題を解決する

最終更新 2023/06/23 8:26
Token
読了目安 4 分
カテゴリ
Blazor
タグ
.NET C# Blazor

本文は転載です

原文著者:Token

原文タイトル:Blazor Serverの煩わしい再接続をキャンセルする方法

原文リンク:https://www.cnblogs.com/hejiale010426/p/17498629.html

多くのBlazorユーザーは、内部システムを開発する際に、速度が速く、読み込みが速いBlazor Serverモードを選択するでしょう。

しかし、Blazor ServerSignalRで実装されているため、アクセス時にWebSocketチャネルが確立され、jsとのやり取りや画面レンダリングに使用されます。WebSocketは長期間接続を維持するため、ユーザーが画面を操作している間、常に接続が維持され、サーバーの帯域幅を占有します。そのため、Microsoftはデフォルトで操作がない場合に自動的に接続を切断し、さらに煩わしい再接続UIを追加します。これは見た目が悪く、多くのユーザーが灰色の効果を見ることになります。もちろん、Microsoftはこの状況に対処する方法も提供しています。以下では、Microsoftが提供する方法を使用してこの問題を解決します。

Blazor Serverの空のプロジェクトを作成する

以下は、作成したばかりのBlazor Serverの空のプロジェクトです。

そして、長時間放置すると以下のような状況になります。

見苦しい読み込みUIで、全面が灰色のスタイルで覆われます。これを削除しましょう。

灰色の読み込みスタイルを削除する

再接続を処理するためのboot.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} / ${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) に割り当てられた値の少なくとも2倍である必要があります。
  • keepAliveIntervalInMilliseconds:サーバーにpingを送信する際のデフォルトの間隔。この設定により、サーバーはクライアントがコンピュータのネットワーク接続を切断するなど、強制的な切断を検出できます。このpingの頻度は、サーバーのpingの頻度と同じ程度までです。サーバーが5秒ごとにpingする場合、5000(5秒)未満の値が割り当てられると、5秒ごとにpingが送信されます。デフォルト値は15秒です。Keep-Alive間隔は、サーバータイムアウト (serverTimeoutInMilliseconds) に割り当てられた値の半分以下である必要があります。

記述後、プログラムを起動し、バックエンドサービスを停止します。すると、上記のUIは表示されなくなりました。

バックエンドが起動すると、フロントエンドと自動的に接続され、フロントエンドに影響を与えることはありません。

終わりに

Token さんからの共有でした。

Blazor 技術交流グループ:452761192

さらに探索

関連読書

その他の記事
同じカテゴリ / 同じタグ 2024/02/29

Winformでもこんなデータ表示ができる

winform開発の過程で、データ表示機能が必要になることがよくあります。これまではgridcontrolコントロールを使用していましたが、今日は例を通して、winform blazor hybridでant design blazorのtableコンポーネントを使ってデータ表示を行う方法を紹介します。

続きを読む
同じカテゴリ / 同じタグ 2024/02/29

Winformの画面も綺麗にできる?

先日、winformでblazor hybridを使用することを紹介しました。また、blazorのUIを組み合わせることでwinformプログラムのデザインをより美しくできると言いました。今回はwinform blazor hybridで描画する例を挙げて説明します。参考になれば幸いです。

続きを読む