ASP.NET Core BlazorSignalR 指引

注意

這不是這篇文章的最新版本。 如需目前版本,請參閱本文的 .NET 8 版本

重要

這些發行前產品的相關資訊在產品正式發行前可能會有大幅修改。 Microsoft 對此處提供的資訊,不做任何明確或隱含的瑕疵擔保。

如需目前版本,請參閱本文的 .NET 8 版本

本文說明如何設定和管理 Blazor 應用程式中的 SignalR 連線。

如需 ASP.NET Core SignalR 組態的一般指引,請參閱文件的 ASP.NET Core SignalR 概觀區域中的主題,特別是 ASP.NET Core SignalR 組態

伺服器端應用程式會使用 ASP.NET Core SignalR 來與瀏覽器通訊。 SignalR 的託管和擴縮條件適用於伺服器端應用程式。

Blazor 在使用 WebSocket 作為 SignalR 傳輸協定時效果最佳,因為其延遲性較低且具備可靠性和安全性。 當 WebSocket 無法使用或當應用程式明確設定為使用長輪詢時,SignalR 就會使用長輪詢。

互動式伺服器元件的 WebSocket 壓縮

依預設,互動式伺服器元件:

  • WebSocket 連線啟用壓縮。 ConfigureWebsocketOptions 會控制 WebSocket 壓縮。

  • 採用設定為 'self'frame-ancestors內容安全原則 (CSP) 指示詞,它只會允許將應用程式內嵌在來源的 <iframe> 中,透過它在啟用壓縮或在提供 WebSocket 內容的設定時提供應用程式。 ContentSecurityFrameAncestorPolicy 會控制 frame-ancestors CSP。

您可以將 ConfigureWebSocketOptions 的值設定為 null,以手動移除 frame-ancestors CSP,因為您可能想要以集中的方式設定 CSP。 以集中的方式管理 frame-ancestors CSP 時,每當轉譯第一份文件時,套用原則時都必須小心。 我們不建議您完全移除原則,因為它可能會讓應用程式容易受到攻擊。

使用範例:

ConfigureWebSocketOptions 設定為 null 可停用壓縮,這可降低應用程式遭受攻擊的弱點,但可能會導致效能降低:

builder.MapRazorComponents<App>()
    .AddInteractiveServerRenderMode(o => o.ConfigureWebSocketOptions = null)

啟用壓縮時,請使用 'none' 值設定較嚴格的 frame-ancestorsCSP,其會允許 WebSocket 壓縮,但會防止瀏覽器將應用程式內嵌至任何 <iframe>

builder.MapRazorComponents<App>()
    .AddInteractiveServerRenderMode(o => o.ContentSecurityFrameAncestorsPolicy = "'none'")

啟用壓縮時,將 ContentSecurityFrameAncestorsPolicy 設定為 null 來移除 frame-ancestors CSP。 此案例僅建議用於以集中方式設定 CSP 的應用程式:

builder.MapRazorComponents<App>()
    .AddInteractiveServerRenderMode(o => o.ContentSecurityFrameAncestorsPolicy = null)

重要

瀏覽器會使用最嚴格的原則指示詞值,從多個 CSP 標頭套用 CSP 指示詞。 因此,開發人員不能故意或錯誤地新增較 'self' 更弱的 frame-ancestors 原則。

傳遞至 ContentSecurityFrameAncestorsPolicy 的字串值需要單引號:

不支援的值:noneself

支援的值:'none''self'

其他選項包括指定一或多個主機來源和配置來源。

如需安全性影響,請參閱 ASP.NET Core Blazor 互動式伺服器端轉譯的威脅風險降低指導。 如需 frame-ancestors 指示詞的詳細資訊,請參閱 CSP:frame-ancestors (MDN 文件)

停用熱重新載入的回應壓縮

使用熱重新載入時,請在 Development 環境中停用回應壓縮中介軟體。 無論是否使用專案範本中的預設程式碼,請一律先在要求處理管線中呼叫 UseResponseCompression

Program 檔案中:

if (!app.Environment.IsDevelopment())
{
    app.UseResponseCompression();
}

用於驗證的用戶端側 SignalR 跨原始來源交涉

本節說明如何設定 SignalR 的基礎用戶端來傳送認證 (例如 cookie 或 HTTP 驗證標題)。

使用 SetBrowserRequestCredentials 在跨原始來源 fetch 要求上設定 Include

IncludeRequestCredentialsMessageHandler.cs

using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.WebAssembly.Http;

public class IncludeRequestCredentialsMessageHandler : DelegatingHandler
{
    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        request.SetBrowserRequestCredentials(BrowserRequestCredentials.Include);
        return base.SendAsync(request, cancellationToken);
    }
}

在建置中樞連線的位置,將 HttpMessageHandler 指派給 HttpMessageHandlerFactory 選項:

private HubConnectionBuilder? hubConnection;

...

hubConnection = new HubConnectionBuilder()
    .WithUrl(new Uri(Navigation.ToAbsoluteUri("/chathub")), options =>
    {
        options.HttpMessageHandlerFactory = innerHandler => 
            new IncludeRequestCredentialsMessageHandler { InnerHandler = innerHandler };
    }).Build();

上述範例會將中樞連線 URL 設定為位於 /chathub 的絕對 URI 位址。 該 URI 也可以透過字串來設定,例如 https://signalr.example.com,或透過組態進行設定。 Navigation 是插入的 NavigationManager

如需詳細資訊,請參閱 ASP.NET Core SignalR 組態

用戶端轉譯

如果已設定預先轉譯,則會在用戶端與伺服器建立連線之前先進行預先轉譯。 如需詳細資訊,請參閱預先轉譯 ASP.NET Core Razor 元件

如果已設定預先轉譯,則會在用戶端與伺服器建立連線之前先進行預先轉譯。 如需詳細資訊,請參閱下列文章:

預先轉譯狀態大小和 SignalR 訊息大小限制

大型預先轉譯狀態大小可能超過 SignalR 線路訊息大小限制,這會導致下列結果:

  • SignalR 線路無法初始化,且用戶端發生錯誤:Circuit host not initialized.
  • 當線路失敗時,用戶端上的重新連線對話方塊隨即出現。 不可能復原。

若要解決該問題,請使用下列任一種方法:

  • 減少放入預先轉譯狀態的資料量。
  • 新增 SignalR 訊息大小限制警告:增加限制可能會增加拒絕服務 (DoS) 攻擊的風險。

其他用戶端側資源

將黏性工作階段用於伺服器端 Webfarm 裝載

Blazor 應用程式會預先轉譯以回應第一個用戶端要求,這會在伺服器上建立 UI 狀態。 當用戶端嘗試建立 SignalR 連線時,用戶端必須重新連線至相同的伺服器。 使用多個後端伺服器時,應用程式應為 SignalR 連線實作黏性工作階段

注意

尚未在 Webfarm 中啟用黏性工作階段的應用程式擲回下列錯誤:

blazor.server.js:1 Uncaught (in promise) 錯誤:因基礎連線關閉而取消叫用。

伺服器端 Azure SignalR 服務

我們建議使用 Azure SignalR 服務在 Microsoft Azure 中進行託管的伺服器端開發。 該服務與應用程式的 Blazor 中樞搭配運作,以將伺服器端應用程式擴展為大量的並行 SignalR 連線。 此外,SignalR 服務的全球觸達和高效能資料中心可大幅協助降低因地理位置造成的延遲。

透過將服務的 ServerStickyMode 選項或組態值設定為 Required,即可為 Azure SignalR 服務啟用黏性工作階段。 如需詳細資訊,請參閱裝載和部署 ASP.NET Core 伺服器端 Blazor 應用程式

伺服器端線路處理常式選項

使用 CircuitOptions 設定線路。 檢視參考來源中的預設值。

注意

.NET 參考來源的文件連結通常會載入存放庫的預設分支,這表示下一版 .NET 的目前開發。 若要選取特定版本的標籤,請使用 [切換分支或標籤] 下拉式清單。 如需詳細資訊,請參閱如何選取 ASP.NET Core 原始程式碼 (dotnet/AspNetCore.Docs #26205) 的版本標籤

使用委派給 AddInteractiveServerComponents 的選項來讀取或設定 Program 檔案中的選項。 {OPTION} 預留位置代表選項,而 {VALUE} 預留位置是值。

Program 檔案中:

builder.Services.AddRazorComponents().AddInteractiveServerComponents(options =>
{
    options.{OPTION} = {VALUE};
});

使用委派給 AddServerSideBlazor 的選項來讀取或設定 Program 檔案中的選項。 {OPTION} 預留位置代表選項,而 {VALUE} 預留位置是值。

Program 檔案中:

builder.Services.AddServerSideBlazor(options =>
{
    options.{OPTION} = {VALUE};
});

使用委派給 AddServerSideBlazor 的選項來讀取或設定 Startup.ConfigureServices 中的選項。 {OPTION} 預留位置代表選項,而 {VALUE} 預留位置是值。

Startup.csStartup.ConfigureServices 中:

services.AddServerSideBlazor(options =>
{
    options.{OPTION} = {VALUE};
});

若要設定 HubConnectionContext,請搭配 AddHubOptions 使用 HubConnectionContextOptions。 檢視參考來源中中樞連線內容選項的預設值。 如需 SignalR 文件中的選項描述,請參閱 ASP.NET Core SignalR 設定{OPTION} 預留位置代表選項,而 {VALUE} 預留位置是值。

注意

.NET 參考來源的文件連結通常會載入存放庫的預設分支,這表示下一版 .NET 的目前開發。 若要選取特定版本的標籤,請使用 [切換分支或標籤] 下拉式清單。 如需詳細資訊,請參閱如何選取 ASP.NET Core 原始程式碼 (dotnet/AspNetCore.Docs #26205) 的版本標籤

Program 檔案中:

builder.Services.AddRazorComponents().AddInteractiveServerComponents().AddHubOptions(options =>
{
    options.{OPTION} = {VALUE};
});

Program 檔案中:

builder.Services.AddServerSideBlazor().AddHubOptions(options =>
{
    options.{OPTION} = {VALUE};
});

Startup.csStartup.ConfigureServices 中:

services.AddServerSideBlazor().AddHubOptions(options =>
{
    options.{OPTION} = {VALUE};
});

警告

MaximumReceiveMessageSize 的預設值為 32 KB。 提高此值可能會增加拒絕服務 (DoS) 攻擊風險。

如需記憶體管理的相關資訊,請參閱裝載和部署 ASP.NET Core 伺服器端 Blazor 應用程式

Blazor 中樞選項

設定 MapBlazorHub 選項來控制 Blazor 中樞的 HttpConnectionDispatcherOptions。 檢視參考來源中中樞連線 Dispatcher 選項的預設值。 {OPTION} 預留位置代表選項,而 {VALUE} 預留位置是值。

注意

.NET 參考來源的文件連結通常會載入存放庫的預設分支,這表示下一版 .NET 的目前開發。 若要選取特定版本的標籤,請使用 [切換分支或標籤] 下拉式清單。 如需詳細資訊,請參閱如何選取 ASP.NET Core 原始程式碼 (dotnet/AspNetCore.Docs #26205) 的版本標籤

app.MapBlazorHub 的呼叫放在應用程式 Program 檔案中的 app.MapRazorComponents 呼叫之後:

app.MapBlazorHub(options =>
{
    options.{OPTION} = {VALUE};
});

在應用程式的 Program 檔案中提供 app.MapBlazorHub 的選項:

app.MapBlazorHub(options =>
{
    options.{OPTION} = {VALUE};
});

在端點路由組態中提供 app.MapBlazorHub 的選項:

app.UseEndpoints(endpoints =>
{
    endpoints.MapBlazorHub(options =>
    {
        options.{OPTION} = {VALUE};
    });
    ...
});

接收訊息大小上限

本節僅適用於實作 SignalR 的專案。

中樞方法允許的傳入 SignalR 訊息大小上限受限於 HubOptions.MaximumReceiveMessageSize (預設值:32 KB)。 SignalR 訊息大於 MaximumReceiveMessageSize 時會擲回錯誤。 該架構不會對從中樞到用戶端的 SignalR 訊息大小施加限制。

如果為將 SignalR 記錄設定為 [偵錯] 或 [追蹤],則訊息大小錯誤僅顯示在瀏覽器的開發人員工具主控台中:

錯誤:連線中斷時出現錯誤「錯誤:伺服器關閉時傳回錯誤:連線已關閉並顯示錯誤」。

SignalR 伺服器端記錄設定為 [偵錯] 或 [追蹤] 時,伺服器端記錄會針對訊息大小錯誤顯示 InvalidDataException

appsettings.Development.json

{
  "DetailedErrors": true,
  "Logging": {
    "LogLevel": {
      ...
      "Microsoft.AspNetCore.SignalR": "Debug"
    }
  }
}

錯誤:

System.IO.InvalidDataException:已超過訊息大小上限 32768B。 您可以在 AddHubOptions 中設定訊息大小。

其中一種方法是透過在 Program 檔案中設定 MaximumReceiveMessageSize 來增加限制。 下列範例會將接收訊息大小上限設定為 64 KB:

builder.Services.AddRazorComponents().AddInteractiveServerComponents()
    .AddHubOptions(options => options.MaximumReceiveMessageSize = 64 * 1024);

提高 SignalR 傳入訊息大小限制,代價是要求更多的伺服器資源,並增加拒絕服務 (DoS) 攻擊的風險。 此外,如果將大量內容以字串或位元組陣列的形式讀入記憶體中,也會導致記憶體回收行程的配置運作狀況不佳,從而產生額外的效能降低。

讀取大型承載的較佳選項是以較小的區塊傳送內容,並將承載作為 Stream 處理。 在讀取大型 JavaScript (JS) 交互操作 JSON 承載時,或是 JS 交互操作資料以原始位元組提供時,可以使用此方法。 如需示範如何使用類似 InputFile 元件的技術在伺服器端應用程式中傳送大型二進位承載的範例,請參閱二進位提交範例應用程式BlazorInputLargeTextArea 元件範例

注意

.NET 參考來源的文件連結通常會載入存放庫的預設分支,這表示下一版 .NET 的目前開發。 若要選取特定版本的標籤,請使用 [切換分支或標籤] 下拉式清單。 如需詳細資訊,請參閱如何選取 ASP.NET Core 原始程式碼 (dotnet/AspNetCore.Docs #26205) 的版本標籤

透過 SignalR 處理大型承載的表單也可以直接使用串流 JS 交互操作。 如需詳細資訊,請參閱在 ASP.NET Core Blazor 中從 JavaScript 函式呼叫 .NET 方法。 如需將 <textarea> 資料串流至伺服器的表單範例,請參閱疑難排解 ASP.NET Core Blazor 表單

其中一種方法是透過在 Program 檔案中設定 MaximumReceiveMessageSize 來增加限制。 下列範例會將接收訊息大小上限設定為 64 KB:

builder.Services.AddServerSideBlazor()
    .AddHubOptions(options => options.MaximumReceiveMessageSize = 64 * 1024);

提高 SignalR 傳入訊息大小限制,代價是要求更多的伺服器資源,並增加拒絕服務 (DoS) 攻擊的風險。 此外,如果將大量內容以字串或位元組陣列的形式讀入記憶體中,也會導致記憶體回收行程的配置運作狀況不佳,從而產生額外的效能降低。

讀取大型承載的較佳選項是以較小的區塊傳送內容,並將承載作為 Stream 處理。 在讀取大型 JavaScript (JS) 交互操作 JSON 承載時,或是 JS 交互操作資料以原始位元組提供時,可以使用此方法。 如需示範如何Blazor Server使用類似 InputFile 元件的技術傳送大型二進位承載的範例,請參閱二進位提交範例應用程式BlazorInputLargeTextArea 元件範例

注意

.NET 參考來源的文件連結通常會載入存放庫的預設分支,這表示下一版 .NET 的目前開發。 若要選取特定版本的標籤,請使用 [切換分支或標籤] 下拉式清單。 如需詳細資訊,請參閱如何選取 ASP.NET Core 原始程式碼 (dotnet/AspNetCore.Docs #26205) 的版本標籤

透過 SignalR 處理大型承載的表單也可以直接使用串流 JS 交互操作。 如需詳細資訊,請參閱在 ASP.NET Core Blazor 中從 JavaScript 函式呼叫 .NET 方法。 如需將 <textarea> 資料串流至 Blazor Server 應用程式的表單範例,請參閱疑難排解 ASP.NET Core Blazor 表單

藉由在 Startup.ConfigureServices 中設定 MaximumReceiveMessageSize 來提高限制:

services.AddServerSideBlazor()
    .AddHubOptions(options => options.MaximumReceiveMessageSize = 64 * 1024);

提高 SignalR 傳入訊息大小限制,代價是要求更多的伺服器資源,並增加拒絕服務 (DoS) 攻擊的風險。 此外,如果將大量內容以字串或位元組陣列的形式讀入記憶體中,也會導致記憶體回收行程的配置運作狀況不佳,從而產生額外的效能降低。

開發用於傳輸大量資料的程式碼時,請考慮下列指引:

  • 將資料分割成較小的片段,並循序傳送資料區段直到伺服器接收所有資料為止。
  • 請勿在 JS 和 C# 程式碼中配置大型物件。
  • 傳送或接收資料時,請勿長時間封鎖主要 UI 執行緒。
  • 在流程完成或取消時,釋放已消耗的記憶體。
  • 為了安全起見,請強制執行下列額外要求:
    • 宣告可傳遞的檔案或資料大小上限。
    • 宣告從用戶端到伺服器的最低上傳速率。
  • 在伺服器接收資料之後,資料可以:
    • 暫時儲存在記憶體緩衝區中,直到收集完所有區段為止。
    • 立即取用。 例如,在收到每個區段時,資料可以立即儲存在資料庫中或寫入磁碟。

Blazor 伺服器端中樞端點路由設定

Program 檔案中,呼叫 MapBlazorHub 以將 BlazorHub 對應至應用程式的預設路徑。 Blazor 指令碼 (blazor.*.js) 自動指向 MapBlazorHub 所建立的端點。

在 UI 中反映伺服器端連線狀態

當用戶端偵測到連線已遺失時,用戶端嘗試重新連線時會向使用者顯示預設 UI。 如果重新連線失敗,則會向使用者提供重試選項。

若要自訂 UI,請定義一個 idcomponents-reconnect-modal 的元素。 下列範例將該元素放在 App 元件中。

App.razor

若要自訂 UI,請定義一個 idcomponents-reconnect-modal 的元素。 下列範例將元素放在主機頁面中。

Pages/_Host.cshtml

若要自訂 UI,請定義一個 idcomponents-reconnect-modal 的元素。 下列範例將元素放在版面配置頁面中。

Pages/_Layout.cshtml

若要自訂 UI,請定義一個 idcomponents-reconnect-modal 的元素。 下列範例將元素放在主機頁面中。

Pages/_Host.cshtml

<div id="components-reconnect-modal">
    There was a problem with the connection!
</div>

注意

如果應用程式轉譯了多個具有 idcomponents-reconnect-modal 的元素,則只有第一個轉譯的元素會接收 CSS 類別變更,以顯示或隱藏該元素。

將下列 CSS 樣式新增至網站的樣式表。

wwwroot/app.css

wwwroot/css/site.css

#components-reconnect-modal {
    display: none;
}

#components-reconnect-modal.components-reconnect-show, 
#components-reconnect-modal.components-reconnect-failed, 
#components-reconnect-modal.components-reconnect-rejected {
    display: block;
}

下表描述了 Blazor 架構套用至 components-reconnect-modal 元素的 CSS 類別。

CSS 類別 表示…
components-reconnect-show 遺失的連線。 用戶端嘗試重新連線。 顯示模式。
components-reconnect-hide 重新建立到伺服器的作用中連線。 隱藏模式。
components-reconnect-failed 重新連線失敗,可能是因為網路故障。 若要嘗試重新連線,請在 JavaScript 中呼叫 window.Blazor.reconnect()
components-reconnect-rejected 已拒絕重新連線。 已連線到伺服器,但伺服器拒絕了連線,且伺服器上的使用者狀態遺失。 若要重新載入應用程式,請在 JavaScript 中呼叫 location.reload()。 出現以下情況時,可能會導致此連線狀態:
  • 伺服器端線路發生當機。
  • 用戶端中斷連線的時長足以讓伺服器卸除使用者的狀態。 使用者元件的執行個體已被處置。
  • 伺服器已重新啟動,或應用程式的背景工作處理序被回收。

透過在網站的 CSS 中為模式元素設定 transition-delay 屬性,自訂重新連線顯示出現之前的延遲。 下列範例將轉換延遲從 500 毫秒 (預設值) 設定為 1,000 毫秒 (1 秒)。

wwwroot/app.css

wwwroot/css/site.css

#components-reconnect-modal {
    transition: visibility 0s linear 1000ms;
}

若要顯示目前的重新連線嘗試,請定義一個 components-reconnect-current-attemptid 的元素。 若要顯示重新連線重試次數上限,請定義一個 components-reconnect-max-retriesid 的元素。 下列範例會遵循上一個範例,將這些元素放置在重新連線嘗試模式元素內。

<div id="components-reconnect-modal">
    There was a problem with the connection!
    (Current reconnect attempt: 
    <span id="components-reconnect-current-attempt"></span> /
    <span id="components-reconnect-max-retries"></span>)
</div>

當自訂重新連線模式出現時,它會根據上述程式碼轉譯類似下列的內容:

There was a problem with the connection! (Current reconnect attempt: 3 / 8)

伺服器端轉譯

根據預設,元件會在用戶端與伺服器建立連線之前在伺服器上預先轉譯。 如需詳細資訊,請參閱預先轉譯 ASP.NET Core Razor 元件

根據預設,元件會在用戶端與伺服器建立連線之前在伺服器上預先轉譯。 如需詳細資訊,請參閱 ASP.NET Core 中的元件標籤協助程式。

監視伺服器端線路活動

使用 CircuitHandler 上的 CreateInboundActivityHandler 方法來監視輸入線路活動。 輸入線路活動是從瀏覽器傳送至伺服器的任何活動,例如 UI 事件或 JavaScript-to-.NET 交互操作呼叫。

例如,您可以使用線路活動處理常式來偵測用戶端是否閒置並記錄其線路識別碼 (Circuit.Id):

using Microsoft.AspNetCore.Components.Server.Circuits;
using Microsoft.Extensions.Options;
using Timer = System.Timers.Timer;

public sealed class IdleCircuitHandler : CircuitHandler, IDisposable
{
    private Circuit? currentCircuit;
    private readonly ILogger logger;
    private readonly Timer timer;

    public IdleCircuitHandler(ILogger<IdleCircuitHandler> logger, 
        IOptions<IdleCircuitOptions> options)
    {
        timer = new Timer
        {
            Interval = options.Value.IdleTimeout.TotalMilliseconds,
            AutoReset = false
        };

        timer.Elapsed += CircuitIdle;
        this.logger = logger;
    }

    private void CircuitIdle(object? sender, System.Timers.ElapsedEventArgs e)
    {
        logger.LogInformation("{CircuitId} is idle", currentCircuit?.Id);
    }

    public override Task OnCircuitOpenedAsync(Circuit circuit, 
        CancellationToken cancellationToken)
    {
        currentCircuit = circuit;

        return Task.CompletedTask;
    }

    public override Func<CircuitInboundActivityContext, Task> CreateInboundActivityHandler(
        Func<CircuitInboundActivityContext, Task> next)
    {
        return context =>
        {
            timer.Stop();
            timer.Start();

            return next(context);
        };
    }

    public void Dispose() => timer.Dispose();
}

public class IdleCircuitOptions
{
    public TimeSpan IdleTimeout { get; set; } = TimeSpan.FromMinutes(5);
}

public static class IdleCircuitHandlerServiceCollectionExtensions
{
    public static IServiceCollection AddIdleCircuitHandler(
        this IServiceCollection services, 
        Action<IdleCircuitOptions> configureOptions)
    {
        services.Configure(configureOptions);
        services.AddIdleCircuitHandler();

        return services;
    }

    public static IServiceCollection AddIdleCircuitHandler(
        this IServiceCollection services)
    {
        services.AddScoped<CircuitHandler, IdleCircuitHandler>();

        return services;
    }
}

Program 檔案中註冊服務。 下列範例會設定五分鐘到五秒的預設閒置逾時,以測試上述 IdleCircuitHandler 實作:

builder.Services.AddIdleCircuitHandler(options => 
    options.IdleTimeout = TimeSpan.FromSeconds(5));

線路活動處理常式還提供了從其他非 Blazor 相依性插入 (DI) 範圍存取範圍 Blazor 服務的方法。 如需詳細資訊與範例,請參閱:

Blazor 啟動

在 Blazor Web 應用程式的 App.razor 檔案中設定 Blazor 應用程式的 SignalR 線路的手動啟動:

Pages/_Host.cshtml 檔案中 (Blazor Server) 設定 Blazor 應用程式的 SignalR 線路的手動啟動:

Pages/_Layout.cshtml 檔案中 (Blazor Server) 設定 Blazor 應用程式的 SignalR 線路的手動啟動:

Pages/_Host.cshtml 檔案中 (Blazor Server) 設定 Blazor 應用程式的 SignalR 線路的手動啟動:

  • autostart="false" 屬性新增至 <script> 指令碼的 blazor.*.js 標記中。
  • 放置一個在載入 Blazor 指令碼之後呼叫 Blazor.start() 的指令碼,並將其置於結尾 </body> 標記中。

停用 autostart 時,應用程式中不依賴該線路的任何方面都會正常運作。 例如,用戶端側路由正常運作。 不過,在呼叫 Blazor.start() 之前,依賴該線路的任何方面無法正常運作。 如果沒有已建立的線路,應用程式行為是無法預測的。 例如,當線路中斷連線時,元件方法無法執行。

如需詳細資訊,包括如何在文件就緒時初始化 Blazor,以及如何鏈結至 JS Promise,請參閱 ASP.NET Core Blazor 啟動

在用戶端上設定 SignalR 逾時和 Keep-Alive

為用戶端設定下列值:

  • withServerTimeout:設定伺服器逾時 (以毫秒為單位)。 如果此逾時已過而未從伺服器接收任何訊息,連線就會終止並出現錯誤。 預設的逾時值是 30 秒。 伺服器逾時應至少是指派給 Keep-Alive 間隔 (withKeepAliveInterval) 的值的兩倍。
  • withKeepAliveInterval:設定 Keep-Alive 間隔 (以毫秒為單位)(Ping 伺服器採用的預設間隔)。 此設定可讓伺服器偵測強制中斷連線的情況,例如用戶端拔除其電腦與網路的連線。 此 Ping 的發生頻率最多與伺服器 Ping 的頻率一樣。 如果伺服器每隔五秒 ping 一次,則指派的值低於 5000 (5 秒),將會每五秒 ping 一次。 預設值為 15 秒。 Keep-Alive 間隔應小於或等於指派給伺服器逾時 (withServerTimeout) 值的一半。

下列的 App.razor 檔案 (Blazor Web 應用程式) 範例顯示了預設值的指派。

Blazor Web 應用程式:

<script src="{BLAZOR SCRIPT}" autostart="false"></script>
<script>
  Blazor.start({
    circuit: {
      configureSignalR: function (builder) {
        builder.withServerTimeout(30000).withKeepAliveInterval(15000);
      }
    }
  });
</script>

下列範例適用於 Pages/_Host.cshtml 檔案 (Blazor Server,.NET 6 中的 ASP.NET Core 除外的所有版本) 或 Pages/_Layout.cshtml 檔案 (Blazor Server,.NET 6 中的 ASP.NET Core)。

Blazor Server:

<script src="{BLAZOR SCRIPT}" autostart="false"></script>
<script>
  Blazor.start({
    configureSignalR: function (builder) {
        builder.withServerTimeout(30000).withKeepAliveInterval(15000);
  });
</script>

在上述範例中,{BLAZOR SCRIPT} 預留位置是 Blazor 指令碼路徑和檔案名稱。 如需指令碼的位置和要使用的路徑,請參閱 ASP.NET Core Blazor 專案結構

在元件中建立中樞連線時,請在 HubConnectionBuilder 上設定 ServerTimeout (預設值:30 秒) 和 KeepAliveInterval (預設值:15 秒)。 在建置 HubConnection 上設定 HandshakeTimeout (預設值:15 秒)。 下列範例顯示了預設值的指派:

protected override async Task OnInitializedAsync()
{
    hubConnection = new HubConnectionBuilder()
        .WithUrl(Navigation.ToAbsoluteUri("/chathub"))
        .WithServerTimeout(TimeSpan.FromSeconds(30))
        .WithKeepAliveInterval(TimeSpan.FromSeconds(15))
        .Build();

    hubConnection.HandshakeTimeout = TimeSpan.FromSeconds(15);

    hubConnection.On<string, string>("ReceiveMessage", (user, message) => ...

    await hubConnection.StartAsync();
}

為用戶端設定下列值:

  • serverTimeoutInMilliseconds:伺服器逾時 (以毫秒為單位)。 如果此逾時已過而未從伺服器接收任何訊息,連線就會終止並出現錯誤。 預設的逾時值是 30 秒。 伺服器逾時應至少是指派給 Keep-Alive 間隔 (keepAliveIntervalInMilliseconds) 的值的兩倍。
  • keepAliveIntervalInMilliseconds:Ping 伺服器採用的預設間隔。 此設定可讓伺服器偵測強制中斷連線的情況,例如用戶端拔除其電腦與網路的連線。 此 Ping 的發生頻率最多與伺服器 Ping 的頻率一樣。 如果伺服器每隔五秒 ping 一次,則指派的值低於 5000 (5 秒),將會每五秒 ping 一次。 預設值為 15 秒。 Keep-Alive 間隔應小於或等於指派給伺服器逾時 (serverTimeoutInMilliseconds) 值的一半。

下列範例適用於 Pages/_Host.cshtml 檔案 (Blazor Server,.NET 6 中的 ASP.NET Core 除外的所有版本) 或 Pages/_Layout.cshtml 檔案 (Blazor Server,.NET 6 中的 ASP.NET Core):

<script src="{BLAZOR SCRIPT}" autostart="false"></script>
<script>
  Blazor.start({
    configureSignalR: function (builder) {
      let c = builder.build();
      c.serverTimeoutInMilliseconds = 30000;
      c.keepAliveIntervalInMilliseconds = 15000;
      builder.build = () => {
        return c;
      };
    }
  });
</script>

在上述範例中,{BLAZOR SCRIPT} 預留位置是 Blazor 指令碼路徑和檔案名稱。 如需指令碼的位置和要使用的路徑,請參閱 ASP.NET Core Blazor 專案結構

在元件中建立中樞連線時,請在建置的 HubConnection 中設定 ServerTimeout (預設值:30 秒)、HandshakeTimeout (預設值:15 秒) 和 KeepAliveInterval (預設值:15 秒)。 下列範例顯示了預設值的指派:

protected override async Task OnInitializedAsync()
{
    hubConnection = new HubConnectionBuilder()
        .WithUrl(Navigation.ToAbsoluteUri("/chathub"))
        .Build();

    hubConnection.ServerTimeout = TimeSpan.FromSeconds(30);
    hubConnection.HandshakeTimeout = TimeSpan.FromSeconds(15);
    hubConnection.KeepAliveInterval = TimeSpan.FromSeconds(15);

    hubConnection.On<string, string>("ReceiveMessage", (user, message) => ...

    await hubConnection.StartAsync();
}

變更伺服器逾時值 (ServerTimeout) 或 Keep-Alive 間隔值 (KeepAliveInterval):

  • 伺服器逾時應至少是指派給 Keep-Alive 間隔的值的兩倍。
  • Keep-Alive 間隔應小於或等於指派給伺服器逾時值的一半。

如需詳細資訊,請參閱下列文章的全域部署和連線失敗章節:

修改伺服器端重新連線處理常式

可以針對自訂行為修改重新連線處理常式的線路連線活動,例如:

  • 在連線中斷時通知使用者。
  • 在線路連線時 (來自用戶端) 執行記錄。

若要修改連線活動,請為下列連線變更註冊回呼:

  • 使用 onConnectionDown 卸除的連線。
  • 使用 onConnectionUp 已建立/重新建立的連線。

必須同時指定 onConnectionDownonConnectionUp

Blazor Web 應用程式:

<script src="{BLAZOR SCRIPT}" autostart="false"></script>
<script>
  Blazor.start({
    circuit: {
      reconnectionHandler: {
        onConnectionDown: (options, error) => console.error(error),
        onConnectionUp: () => console.log("Up, up, and away!")
      }
    }
  });
</script>

Blazor Server:

<script src="{BLAZOR SCRIPT}" autostart="false"></script>
<script>
  Blazor.start({
    reconnectionHandler: {
      onConnectionDown: (options, error) => console.error(error),
      onConnectionUp: () => console.log("Up, up, and away!")
    }
  });
</script>

在上述範例中,{BLAZOR SCRIPT} 預留位置是 Blazor 指令碼路徑和檔案名稱。 如需指令碼的位置和要使用的路徑,請參閱 ASP.NET Core Blazor 專案結構

伺服器端重新連線失敗後自動重新整理頁面

預設重新連線行為需要使用者在重新連線失敗之後,手動重新整理頁面。 不過,您可使用自訂重新連線處理常式來自動重新整理頁面:

App.razor

Pages/_Host.cshtml

<div id="reconnect-modal" style="display: none;"></div>
<script src="{BLAZOR SCRIPT}" autostart="false"></script>
<script src="boot.js"></script>

在上述範例中,{BLAZOR SCRIPT} 預留位置是 Blazor 指令碼路徑和檔案名稱。 如需指令碼的位置和要使用的路徑,請參閱 ASP.NET Core Blazor 專案結構

建立下列 wwwroot/boot.js 檔案。

Blazor Web 應用程式:

(() => {
  const maximumRetryCount = 3;
  const retryIntervalMilliseconds = 5000;
  const reconnectModal = document.getElementById('reconnect-modal');

  const startReconnectionProcess = () => {
    reconnectModal.style.display = 'block';

    let isCanceled = false;

    (async () => {
      for (let i = 0; i < maximumRetryCount; i++) {
        reconnectModal.innerText = `Attempting to reconnect: ${i + 1} of ${maximumRetryCount}`;

        await new Promise(resolve => setTimeout(resolve, retryIntervalMilliseconds));

        if (isCanceled) {
          return;
        }

        try {
          const result = await Blazor.reconnect();
          if (!result) {
            // The server was reached, but the connection was rejected; reload the page.
            location.reload();
            return;
          }

          // Successfully reconnected to the server.
          return;
        } catch {
          // Didn't reach the server; try again.
        }
      }

      // Retried too many times; reload the page.
      location.reload();
    })();

    return {
      cancel: () => {
        isCanceled = true;
        reconnectModal.style.display = 'none';
      },
    };
  };

  let currentReconnectionProcess = null;

  Blazor.start({
    circuit: {
      reconnectionHandler: {
        onConnectionDown: () => currentReconnectionProcess ??= startReconnectionProcess(),
        onConnectionUp: () => {
          currentReconnectionProcess?.cancel();
          currentReconnectionProcess = null;
        }
      }
    }
  });
})();

Blazor Server:

(() => {
  const maximumRetryCount = 3;
  const retryIntervalMilliseconds = 5000;
  const reconnectModal = document.getElementById('reconnect-modal');

  const startReconnectionProcess = () => {
    reconnectModal.style.display = 'block';

    let isCanceled = false;

    (async () => {
      for (let i = 0; i < maximumRetryCount; i++) {
        reconnectModal.innerText = `Attempting to reconnect: ${i + 1} of ${maximumRetryCount}`;

        await new Promise(resolve => setTimeout(resolve, retryIntervalMilliseconds));

        if (isCanceled) {
          return;
        }

        try {
          const result = await Blazor.reconnect();
          if (!result) {
            // The server was reached, but the connection was rejected; reload the page.
            location.reload();
            return;
          }

          // Successfully reconnected to the server.
          return;
        } catch {
          // Didn't reach the server; try again.
        }
      }

      // Retried too many times; reload the page.
      location.reload();
    })();

    return {
      cancel: () => {
        isCanceled = true;
        reconnectModal.style.display = 'none';
      },
    };
  };

  let currentReconnectionProcess = null;

  Blazor.start({
    reconnectionHandler: {
      onConnectionDown: () => currentReconnectionProcess ??= startReconnectionProcess(),
      onConnectionUp: () => {
        currentReconnectionProcess?.cancel();
        currentReconnectionProcess = null;
      }
    }
  });
})();

如需關於 Blazor 啟動的詳細資訊,請參閱 ASP.NET Core Blazor 啟動

調整伺服器端重新連線重試次數和間隔

若要調整重新連線重試次數和間隔,請設定重試次數 (maxRetries) 和允許每次重試的間隔毫秒數 (retryIntervalMilliseconds)。

Blazor Web 應用程式:

<script src="{BLAZOR SCRIPT}" autostart="false"></script>
<script>
  Blazor.start({
    circuit: {
      reconnectionOptions: {
        maxRetries: 3,
        retryIntervalMilliseconds: 2000
      }
    }
  });
</script>

Blazor Server:

<script src="{BLAZOR SCRIPT}" autostart="false"></script>
<script>
  Blazor.start({
    reconnectionOptions: {
      maxRetries: 3,
      retryIntervalMilliseconds: 2000
    }
  });
</script>

在上述範例中,{BLAZOR SCRIPT} 預留位置是 Blazor 指令碼路徑和檔案名稱。 如需指令碼的位置和要使用的路徑,請參閱 ASP.NET Core Blazor 專案結構

如需關於 Blazor 啟動的詳細資訊,請參閱 ASP.NET Core Blazor 啟動

控制重新連線 UI 的出現時機

在下列情況中,可能會需要控制重新連線 UI 的出現時機:

  • 已部署的應用程式因為網際網路延遲造成 Ping 逾時而經常顯示重新連線 UI,而您想要增加延遲閾值。
  • 某個應用程式需要在更短時間內向使用者回報連線已中斷,因此您想要縮短延遲閾值。

調整用戶端上的保持運作 (Keep-Alive) 間隔和逾時,將會影響重新連線 UI 出現的時機。 當用戶端上達到伺服器逾時 (withServerTimeout用戶端組態區段),就會顯示重新連線 UI。 不過,變更 withServerTimeout 的值需要變更下列指引中所述的其他 Keep-Alive、逾時和交握設定。

作為指導的一般建議如下:

  • 用戶端和伺服器設定的保持運作間隔應相符。
  • 逾時應該至少是保持運作間隔指派值的兩倍。

伺服器組態

設定下列內容:

  • ClientTimeoutInterval (預設值:30 秒):用戶端必須傳送訊息以避免伺服器關閉連線的時間範圍。
  • HandshakeTimeout (預設值:15 秒):伺服器針對用戶端傳入交握要求逾時所採用的間隔。
  • KeepAliveInterval (預設值:15 秒):伺服器將保持運作 Ping 傳送給已連線用戶端所採用的間隔。 請注意,用戶端上也有保持運作間隔設定,該值應符合伺服器的值。

ClientTimeoutIntervalHandshakeTimeout 可以增加,而 KeepAliveInterval 可以維持不變。 重要的考量是,如果您變更該值,請確定逾時至少是保持運作間隔值的兩倍,且伺服器和用戶端的保持運作間隔相符。 如需詳細資訊,請參閱在用戶端上設定 SignalR 逾時和 Keep-Alive 一節。

在以下範例中:

  • ClientTimeoutInterval 會增加到 60 秒 (預設值:30 秒)。
  • HandshakeTimeout 會增加到 30 秒 (預設值:15 秒)。
  • KeepAliveInterval 未在開發人員程式代碼中設定 ,並使用其預設值 15 秒。 減少保持運作間隔的值會增加通訊 Ping 的頻率,從而增加應用程式、伺服器和網路上的負載。 請務必謹慎避免降低保持運作間隔所導致的效能不佳。

伺服器專案 Program 檔案中的 Blazor Web 應用程式 (.NET 8 或更新版本):

builder.Services.AddRazorComponents().AddInteractiveServerComponents()
    .AddHubOptions(options =>
{
    options.ClientTimeoutInterval = TimeSpan.FromSeconds(60);
    options.HandshakeTimeout = TimeSpan.FromSeconds(30);
});

Program 檔案中的 Blazor Server

builder.Services.AddServerSideBlazor()
    .AddHubOptions(options =>
    {
        options.ClientTimeoutInterval = TimeSpan.FromSeconds(60);
        options.HandshakeTimeout = TimeSpan.FromSeconds(30);
    });

如需詳細資訊,請參閱伺服器端線路處理常式選項一節。

用戶端組態

設定下列內容:

  • withServerTimeout (預設值:30 秒):為線路中樞連線設定以毫秒為單位的伺服器逾時。
  • withKeepAliveInterval (預設值:15 秒):連線傳送保持運作訊息的間隔,以毫秒為單位。

伺服器逾時可以增加,而保持運作間隔可以維持不變。 重要的考量是,如果您變更該值,請確定伺服器逾時至少是保持運作間隔值的兩倍,且伺服器和用戶端的保持運作間隔值相符。 如需詳細資訊,請參閱在用戶端上設定 SignalR 逾時和 Keep-Alive 一節。

在下列啟動設定範例 (Blazor 指令碼的位置) 中,伺服器逾時會使用 60 秒的自訂值。 保持運作間隔 (withKeepAliveInterval) 未設定,並使用其預設值 15 秒。

Blazor Web 應用程式:

<script src="{BLAZOR SCRIPT}" autostart="false"></script>
<script>
  Blazor.start({
    circuit: {
      configureSignalR: function (builder) {
        builder.withServerTimeout(60000);
      }
    }
  });
</script>

Blazor Server:

<script src="{BLAZOR SCRIPT}" autostart="false"></script>
<script>
  Blazor.start({
    configureSignalR: function (builder) {
      builder.withServerTimeout(60000);
    }
  });
</script>

在元件中建立中樞連線時,請在 HubConnectionBuilder 上設定伺服器逾時 (WithServerTimeout,預設值:30 秒)。 在建置 HubConnection 上設定 HandshakeTimeout (預設值:15 秒)。 確認逾時至少是保持運作間隔 (WithKeepAliveInterval/KeepAliveInterval) 的兩倍,且保持運作值在伺服器和用戶端之間相符。

下列範例是以 SignalR 與 Blazor 教學課程中的 Index 元件為基礎。 伺服器逾時值會增加到 60 秒,交握逾時值則會增加到 30 秒。 保持運作間隔未設定,並使用其預設值 15 秒。

protected override async Task OnInitializedAsync()
{
    hubConnection = new HubConnectionBuilder()
        .WithUrl(Navigation.ToAbsoluteUri("/chathub"))
        .WithServerTimeout(TimeSpan.FromSeconds(60))
        .Build();

    hubConnection.HandshakeTimeout = TimeSpan.FromSeconds(30);

    hubConnection.On<string, string>("ReceiveMessage", (user, message) => ...

    await hubConnection.StartAsync();
}

設定下列內容:

  • serverTimeoutInMilliseconds (預設值:30 秒):為線路中樞連線設定以毫秒為單位的伺服器逾時。
  • keepAliveIntervalInMilliseconds (預設值:15 秒):連線傳送保持運作訊息的間隔,以毫秒為單位。

伺服器逾時可以增加,而保持運作間隔可以維持不變。 重要的考量是,如果您變更該值,請確定伺服器逾時至少是保持運作間隔值的兩倍,且伺服器和用戶端的保持運作間隔值相符。 如需詳細資訊,請參閱在用戶端上設定 SignalR 逾時和 Keep-Alive 一節。

在下列啟動設定範例 (Blazor 指令碼的位置) 中,伺服器逾時會使用 60 秒的自訂值。 保持運作間隔 (keepAliveIntervalInMilliseconds) 未設定,並使用其預設值 15 秒。

Pages/_Host.cshtml 中:

<script src="_framework/blazor.server.js" autostart="false"></script>
<script>
  Blazor.start({
    configureSignalR: function (builder) {
      let c = builder.build();
      c.serverTimeoutInMilliseconds = 60000;
      builder.build = () => {
        return c;
      };
    }
  });
</script>

在元件中建立中樞連線時,請在組建 HubConnection 上設定 ServerTimeout (預設值:30 秒) 和 HandshakeTimeout (預設值:15 秒)。 確認逾時至少是保持運作間隔的兩倍。 確認伺服器與用戶端之間的保持運作間隔相符。

下列範例是以 SignalR 與 Blazor 教學課程中的 Index 元件為基礎。 ServerTimeout 會增加到 60 秒,而 HandshakeTimeout 會增加到 30 秒。 保持運作間隔 (KeepAliveInterval) 未設定,並使用其預設值 15 秒。

protected override async Task OnInitializedAsync()
{
    hubConnection = new HubConnectionBuilder()
        .WithUrl(Navigation.ToAbsoluteUri("/chathub"))
        .Build();

    hubConnection.ServerTimeout = TimeSpan.FromSeconds(60);
    hubConnection.HandshakeTimeout = TimeSpan.FromSeconds(30);

    hubConnection.On<string, string>("ReceiveMessage", (user, message) => ...

    await hubConnection.StartAsync();
}

中斷用戶端與 Blazor 線路的連線

根據預設,觸發 unload 頁面事件時,Blazor 線路會中斷連線。 若要中斷用戶端上其他案例的線路連線,請在適當的事件處理常式中叫用 Blazor.disconnect。 在下列範例中,當頁面隱藏 (pagehide 事件) 時,線路會中斷連線:

window.addEventListener('pagehide', () => {
  Blazor.disconnect();
});

如需關於 Blazor 啟動的詳細資訊,請參閱 ASP.NET Core Blazor 啟動

伺服器端線路處理常式

您可以定義線路處理常式,以允許在使用者線路狀態發生變更時執行程式碼。 線路處理常式是透過衍生自 CircuitHandler 並將該類別註冊至應用程式服務容器中來實作。 下列線路處理常式範例會追蹤開啟的 SignalR 連線。

TrackingCircuitHandler.cs

using Microsoft.AspNetCore.Components.Server.Circuits;

public class TrackingCircuitHandler : CircuitHandler
{
    private HashSet<Circuit> circuits = new();

    public override Task OnConnectionUpAsync(Circuit circuit, 
        CancellationToken cancellationToken)
    {
        circuits.Add(circuit);

        return Task.CompletedTask;
    }

    public override Task OnConnectionDownAsync(Circuit circuit, 
        CancellationToken cancellationToken)
    {
        circuits.Remove(circuit);

        return Task.CompletedTask;
    }

    public int ConnectedCircuits => circuits.Count;
}

線路處理常式是使用 DI 註冊。 每個線路執行個體都會建立範圍的執行個體。 使用上述範例中的 TrackingCircuitHandler 建立單一服務,因為必須追蹤所有線路的狀態。

Program 檔案中:

builder.Services.AddSingleton<CircuitHandler, TrackingCircuitHandler>();

Startup.csStartup.ConfigureServices 中:

services.AddSingleton<CircuitHandler, TrackingCircuitHandler>();

如果自訂線路處理常式的方法擲回未處理的例外狀況,則此例外狀況會導致線路產生嚴重錯誤。 若要容許處理常式程式碼或呼叫方法中的例外狀況,請使用錯誤處理和記錄將程式碼包裝到一或多個 try-catch 陳述式中。

當線路因使用者已中斷連線而結束,且架構正在清除線路狀態時,架構會處置線路的 DI 範圍。 處置範圍會處置任何實作 System.IDisposable 的線路範圍 DI 服務。 如果任何 DI 服務在處置期間擲回未處理的例外狀況,架構會記錄例外狀況。 如需詳細資訊,請參閱 ASP.NET Core Blazor 相依性插入

用於為自訂服務擷取使用者的伺服器端線路處理常式

使用 CircuitHandlerAuthenticationStateProvider 擷取使用者,並在服務中設定該使用者。 如需詳細資訊和範例程式碼,請參閱伺服器端 ASP.NET Core Blazor 其他安全性案例

沒有剩餘的互動式伺服器元件時關閉線路

互動式伺服器元件會使用與瀏覽器的即時連線來處理 Web UI 事件,稱為線路。 當轉譯根互動式伺服器元件時,會建立線路及其相關聯的狀態。 當頁面上沒有剩餘的互動式伺服器元件時,線路會關閉並釋放伺服器資源。

Razor 元件中的 IHttpContextAccessor/HttpContext

IHttpContextAccessor 必須避免使用互動式轉譯,因為沒有有效的 HttpContext 可用。

IHttpContextAccessor 可用於伺服器上靜態轉譯的元件。 不過,建議您盡可能避免。

只能在一般工作的靜態轉譯根元件中將 HttpContext 用作 級聯參數,例如檢查和修改 App 元件 (Components/App.razor) 中的標頭或其他屬性。 用於互動式轉譯的值一律是 null

[CascadingParameter]
public HttpContext? HttpContext { get; set; }

針對互動式元件中所需 HttpContext 的案例,建議您透過伺服器的持續元件狀態來流動資料。 如需詳細資訊,請參閱 伺服器端 ASP.NET Core Blazor的其他安全性案例

請勿在伺服器端 Blazor 應用程式的 Razor 元件中直接或間接使用 IHttpContextAccessor/HttpContext Blazor 應用程式會在 ASP.NET Core 管線內容之外執行。 既不保證 HttpContextIHttpContextAccessor 中可用,也不保證 HttpContext 會保留啟動了 Blazor 應用程式的內容。

建議在 Blazor 應用程式的初始轉譯期間,透過根元件參數將要求狀態傳遞給此應用程式。 或者,應用程式可以將資料複製到根元件初始化生命週期事件中的範圍服務,以便在整個應用程式中使用。 如需詳細資訊,請參閱伺服器端 ASP.NET Core Blazor 其他安全性案例

伺服器端 Blazor 安全性的一個重要層面是,附加至指定線路的使用者可能會在建立 Blazor 線路後的某個時間點進行更新,但 IHttpContextAccessor 不會更新。 如需使用自訂服務解決這種情況的詳細資訊,請參閱伺服器端 ASP.NET Core Blazor 其他安全性案例

其他伺服器端資源