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

2023-06-23 06:00:32

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

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

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

建立Blazor Server的空專案

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

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

很醜的載入ui,灰色的全面覆蓋樣式,下面就得幹掉這個。

去掉灰色載入樣式。

新增boot.jsjs指令碼,用於處理重新連線

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">