注意
這不是這篇文章的最新版本。 如需目前的版本,請參閱 本文的 .NET 9 版本。
警告
不再支援此版本的 ASP.NET Core。 如需詳細資訊,請參閱 .NET 和 .NET Core 支持原則。 如需目前的版本,請參閱 本文的 .NET 9 版本。
本文說明如何設定和管理 SignalR 應用程式中的 Blazor 連線。
如需 ASP.NET Core SignalR 組態的一般指引,請參閱文件的 ASP.NET Core SignalR 概觀區域中的主題,特別是 ASP.NET Core SignalR 組態。
伺服器端應用程式會使用 ASP.NET Core SignalR 來與瀏覽器通訊。 SignalR 的託管和擴縮條件適用於伺服器端應用程式。
Blazor 在使用 WebSocket 作為 SignalR 傳輸協定時效果最佳,因為其延遲性較低且具備可靠性和安全性。 當 WebSocket 無法使用時或應用程式明確設定為使用長輪詢時,SignalR 就會使用長輪詢。
具狀態重新連線的 Azure SignalR 服務
Azure SignalR 服務搭配 SDK v1.26.1 或更新版本,支援 SignalR 具狀態的重新連線(WithStatefulReconnect)。
互動伺服器元件的 WebSocket 壓縮
依預設,互動式伺服器元件:
為 WebSocket 連線啟用壓縮。 DisableWebSocketCompression (預設值:
false
)控制 WebSocket 壓縮。frame-ancestors
採用設定為'self'
的內容安全策略 (CSP) 指示詞,這是預設值,且只允許在啟用壓縮時或提供 WebSocket 內容設定時,將應用程式內嵌在<iframe>
來源的 應用程式中。
如果您想要以集中式方式設定 CSP,可以將frame-ancestors
的預設設為ContentSecurityFrameAncestorsPolicynull
,或設為'none'
以便更嚴格的原則。 當以集中的方式管理 frame-ancestors
CSP 時,必須小心地在首次呈現文件時套用政策。 我們不建議您完全移除原則,因為這會使應用程式容易受到攻擊。 如需詳細資訊,請參閱為 ASP.NET Core Blazor強制執行內容安全策略和 MDN CSP 指南。
使用 ConfigureWebSocketAcceptContext 來為伺服器元件所用的 WebSocket 連線進行WebSocketAcceptContext設定。 根據預設,會套用在 ContentSecurityFrameAncestorsPolicy 中定義的框架祖先啟用壓縮並設定 CSP 的原則。
使用範例:
將 DisableWebSocketCompression 設定為 true
可停用壓縮,這可降低應用程式遭受攻擊的弱點,但可能會導致效能降低:
builder.MapRazorComponents<App>()
.AddInteractiveServerRenderMode(o => o.DisableWebSocketCompression = true)
啟用壓縮時,請設定frame-ancestors
更嚴格的 CSP,其值為'none'
(需要使用單引號),允許 WebSocket 壓縮,但會防止瀏覽器將應用程式嵌入 <iframe>
。
builder.MapRazorComponents<App>()
.AddInteractiveServerRenderMode(o => o.ContentSecurityFrameAncestorsPolicy = "'none'")
啟用壓縮時,將 frame-ancestors
設定為 ContentSecurityFrameAncestorsPolicy 來移除 null
CSP。 此案例僅建議用於以集中方式設定 CSP 的應用程式:
builder.MapRazorComponents<App>()
.AddInteractiveServerRenderMode(o => o.ContentSecurityFrameAncestorsPolicy = null)
重要
瀏覽器會從多個 CSP 標頭中使用最嚴格的政策指令值來套用 CSP 指令。 因此,開發人員不能故意或錯誤地新增較 frame-ancestors
更弱的 'self'
原則。
傳遞至 ContentSecurityFrameAncestorsPolicy 的字串值需要單引號:
不支援的值:none
、self
支援的值:'none'
、'self'
其他選項包括指定一或多個主機來源和結構來源。
如需安全性影響,請參閱 ASP.NET Core Blazor 互動式伺服器端轉譯的威脅風險降低指導。 如需詳細資訊,請參閱針對 ASP.NET Core Blazor和 CSP 強制執行內容安全策略: frame-ancestors
(MDN 檔)。
停用熱重新載入的響應壓縮
使用熱重新載入時,請在 Development
環境中停用回應壓縮中介軟體。 無論是否使用專案範本中的預設程式碼,請一律先在要求處理管線中呼叫 UseResponseCompression。
在 Program
檔案中:
if (!app.Environment.IsDevelopment())
{
app.UseResponseCompression();
}
客戶端 SignalR 跨原始來源用於驗證的協商
本節說明如何設定 SignalR 的底層用戶端傳送憑證,例如 Cookie 或 HTTP 認證標頭。
使用 SetBrowserRequestCredentials 設定 Include 在跨原始來源 fetch
要求中。
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 訊息大小限制
大型預先呈現的狀態大小可能超過 Blazor線路 SignalR 訊息大小限制,這會導致下列結果:
- SignalR 線路無法初始化,且用戶端發生錯誤:Circuit host not initialized.
- 當線路發生中斷時,用戶端會出現重新連線的 UI。 不可能復原。
若要解決該問題,請使用下列任一種方法:
- 減少放入預渲染狀態的資料量。
- 新增 SignalR 訊息大小限制。 警告:增加限制可能會增加拒絕服務 (DoS) 攻擊的風險。
其他用戶端側資源
- 保護 SignalR 中樞
- ASP.NET Core SignalR 概觀
- ASP.NET Core SignalR 組態
-
Blazor 範例 GitHub 存放庫 (
dotnet/blazor-samples
) (如何下載)
使用會話親和性(黏性會話)進行伺服器端網站群組託管
使用多個後端伺服器時,應用程式必須實現會話黏性,也稱為黏性工作階段。 工作階段親和性可確保如果中斷連線,用戶端的線路會重新連線到相同的伺服器,這很重要,因為客戶端狀態只會保留在第一次建立用戶端線路的伺服器記憶體中。
未在 webfarm 中啟用工作階段親和性的應用程式會擲回下列錯誤:
Uncaught (in promise) Error: Invocation canceled due to the underlying connection being closed.
有關 Azure App Service 托管的工作階段親和性的更多資訊,請參閱主機和部署 ASP.NET Core 伺服端 Blazor 應用程式。
Azure SignalR 服務
可選的 Azure SignalR Service 與應用程式的 SignalR 集線器配合使用,可將伺服器端應用程式擴充至大量的同時連線。 此外,服務的全球觸達和高效能資料中心可大幅協助降低因地理位置造成的延遲。
在 Azure App Service 或 Azure Container Apps 中託管的 Blazor 應用程式不需要這項服務,但在其他託管環境中可能會有所幫助:
- 為了方便連線向外延展。
- 處理全球配送。
如需詳細資訊,請參閱裝載和部署 ASP.NET Core 伺服器端 Blazor 應用程式。
伺服器端電路處理程序選項
使用 CircuitOptions 設定線路。 檢視參考來源中的預設值。
注意
.NET 參考來源的文件連結通常會載入儲存庫的預設分支,此分支代表著下一版 .NET 的正在進行的開發。 若要選取特定版本的標籤,請使用 [切換分支或標籤] 下拉式清單。 如需詳細資訊,請參閱如何選取 ASP.NET Core 原始程式碼 (dotnet/AspNetCore.Docs #26205) 的版本標籤。
使用委派給 Program
的選項來讀取或設定 AddInteractiveServerComponents 檔案中的選項。
{OPTION}
預留位置代表選項,而 {VALUE}
預留位置是值。
在 Program
檔案中:
builder.Services.AddRazorComponents().AddInteractiveServerComponents(options =>
{
options.{OPTION} = {VALUE};
});
使用委派給 Program
的選項來讀取或設定 AddServerSideBlazor 檔案中的選項。
{OPTION}
預留位置代表選項,而 {VALUE}
預留位置是值。
在 Program
檔案中:
builder.Services.AddServerSideBlazor(options =>
{
options.{OPTION} = {VALUE};
});
使用委派給 Startup.ConfigureServices
的選項來讀取或設定 AddServerSideBlazor 中的選項。
{OPTION}
預留位置代表選項,而 {VALUE}
預留位置是值。
在 Startup.ConfigureServices
的 Startup.cs
中:
services.AddServerSideBlazor(options =>
{
options.{OPTION} = {VALUE};
});
若要設定 HubConnectionContext,請搭配 HubConnectionContextOptions 使用 AddHubOptions。 檢視參考來源中中樞連線內容選項的預設值。 如需 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.ConfigureServices
的 Startup.cs
中:
services.AddServerSideBlazor().AddHubOptions(options =>
{
options.{OPTION} = {VALUE};
});
警告
MaximumReceiveMessageSize 的預設值為 32 KB。 提高此值可能會增加拒絕服務 (DoS) 攻擊風險。
Blazor 依賴 MaximumParallelInvocationsPerClient 設定為 1,這是預設值。 如需詳細資訊,請參閱 MaximumParallelInvocationsPerClient > 1 在 Blazor Server 模式 (dotnet/aspnetcore
#53951) 時會中斷檔案上傳。
如需記憶體管理的相關信息,請參閱 管理已部署 ASP.NET Core 伺服器端 Blazor 應用程式中的記憶體。
Blazor 中樞選項
設定 MapBlazorHub 選項來控制 HttpConnectionDispatcherOptions 的 Blazor 中樞。 檢視參考來源中中樞連線 Dispatcher 選項的預設值。
{OPTION}
預留位置代表選項,而 {VALUE}
預留位置是值。
注意
.NET 參考來源的文件連結通常會載入存放庫的預設分支,這表示下一版 .NET 的目前開發。 若要選取特定版本的標籤,請使用 [切換分支或標籤] 下拉式清單。 如需詳細資訊,請參閱如何選取 ASP.NET Core 原始程式碼 (dotnet/AspNetCore.Docs #26205) 的版本標籤。
將 app.MapBlazorHub
的呼叫放在應用程式 app.MapRazorComponents
檔案中的 Program
呼叫之後:
app.MapBlazorHub(options =>
{
options.{OPTION} = {VALUE};
});
在用 MapBlazorHub 配置 AddInteractiveServerRenderMode 使用的中樞時失敗,出現 AmbiguousMatchException
:
Microsoft.AspNetCore.Routing.Matching.AmbiguousMatchException: The request matched multiple endpoints.
若要解決以 .NET 8 為目標的應用程式發生的問題,請使用 Blazor 方法為自訂設定的 WithOrder 的中樞提供較高的優先順序:
app.MapBlazorHub(options =>
{
options.CloseOnAuthenticationExpiration = true;
}).WithOrder(-1);
如需詳細資訊,請參閱以下資源:
在應用程式的 app.MapBlazorHub
檔案中提供 Program
的選項:
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 中設定訊息大小。
其中一種方法是透過在 MaximumReceiveMessageSize 檔案中設定 Program
來增加限制。 下列範例會將接收訊息大小上限設定為 64 KB:
builder.Services.AddRazorComponents().AddInteractiveServerComponents()
.AddHubOptions(options => options.MaximumReceiveMessageSize = 64 * 1024);
提高 SignalR 傳入訊息大小限制,代價是要求更多的伺服器資源,並增加拒絕服務 (DoS) 攻擊的風險。 此外,如果將大量內容以字串或位元組陣列的形式讀入記憶體中,也會導致配置與記憶體回收器不兼容,從而產生額外的效能懲罰。
讀取大型承載的較佳選項是以較小的區塊傳送內容,並將承載作為 Stream 處理。 當讀取大型 JavaScript (InputFile
元件的技術在伺服器端應用程式中傳送大型二進位承載的範例,請參閱二進位提交範例應用程式和 BlazorInputLargeTextArea
元件範例。
注意
文件連結至 .NET 參考來源通常會載入存放庫的預設分支(branch),這代表未來發行的 .NET 的當前開發狀態。 若要選取特定版本的標籤,請使用 [切換分支或標籤] 下拉式清單。 如需詳細資訊,請參閱如何選取 ASP.NET Core 原始程式碼 (dotnet/AspNetCore.Docs #26205) 的版本標籤。
透過 SignalR 處理大型負載的表單也可以直接使用串流 JS 互操作。 如需詳細資訊,請參閱在 ASP.NET Core Blazor 中從 JavaScript 函式呼叫 .NET 方法。 如需將 <textarea>
資料串流至伺服器的表單範例,請參閱疑難排解 ASP.NET Core Blazor 表單。
其中一種方法是透過在 MaximumReceiveMessageSize 檔案中設定 Program
來增加限制。 下列範例會將接收訊息大小上限設定為 64 KB:
builder.Services.AddServerSideBlazor()
.AddHubOptions(options => options.MaximumReceiveMessageSize = 64 * 1024);
提高 SignalR 傳入訊息大小限制,代價是要求更多的伺服器資源,並增加拒絕服務 (DoS) 攻擊的風險。 此外,如果將大量內容以字串或位元組陣列的形式讀入記憶體中,也會導致配置與記憶體回收器不兼容,從而產生額外的效能懲罰。
讀取大型承載的較佳選項是以較小的區塊傳送內容,並將承載作為 Stream 處理。 當讀取大型 JavaScript (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 表單。
藉由在 MaximumReceiveMessageSize 中設定 Startup.ConfigureServices
來提高限制:
services.AddServerSideBlazor()
.AddHubOptions(options => options.MaximumReceiveMessageSize = 64 * 1024);
提高 SignalR 傳入訊息大小限制,代價是要求更多的伺服器資源,並增加拒絕服務 (DoS) 攻擊的風險。 此外,如果將大量內容以字串或位元組陣列的形式讀入記憶體中,也會導致配置與記憶體回收器不兼容,從而產生額外的效能懲罰。
開發用於傳輸大量資料的程式碼時,請考慮下列指引:
- 利用原生串流 JS 交互操作支援來傳輸大於 SignalR 傳入訊息大小限制的資料:
- 一般提示:
- 請勿在 JS 和 C# 程式碼中配置大型物件。
- 在流程完成或取消時,釋放已消耗的記憶體。
- 為了安全起見,請強制執行下列額外要求:
- 宣告可傳遞的檔案或資料大小上限。
- 宣告從用戶端到伺服器的最低上傳速率。
- 伺服器接收到資料後,這些資料可以:
- 暫時儲存在記憶體緩衝區中,直到收集完所有區段為止。
- 立即取用。 例如,在收到每個區段時,資料可以立即儲存在資料庫中或寫入磁碟。
- 將資料分割成較小的片段,並循序傳送資料區段直到伺服器接收所有資料為止。
- 請勿在 JS 和 C# 程式碼中配置大型物件。
- 傳送或接收資料時,請勿長時間封鎖主要 UI 執行緒。
- 在流程完成或取消時,釋放已消耗的記憶體。
- 為了安全起見,請強制執行下列額外要求:
- 宣告可傳遞的檔案或資料大小上限。
- 宣告從用戶端到伺服器的最低上傳速率。
- 在伺服器接收到資料後,資料可以被處理為:
- 暫時儲存在記憶體緩衝區中,直到收集完所有區段為止。
- 立即取用。 例如,在收到每個區段時,資料可以立即儲存在資料庫中或寫入磁碟。
Blazor 伺服器端中樞端點路由設定
在 Program
檔案中,呼叫 MapBlazorHub 以將 BlazorHub 對應至應用程式的預設路徑。
Blazor 指令碼 (blazor.*.js
) 自動指向 MapBlazorHub 所建立的端點。
在 UI 中反映伺服器端連線狀態
如果客戶端偵測到與伺服器的連線遺失,客戶端嘗試重新連線時,就會向使用者顯示預設UI:
如果重新連線失敗,則會指示使用者重試或重載頁面:
如果重新連線成功,用戶狀態通常會遺失。 自定義程式代碼可以新增至任何元件,以跨連線失敗儲存和重載用戶狀態。 如需詳細資訊,請參閱 ASP.NET Core Blazor 狀態管理。
若要建立追蹤重新連線狀態的 UI 元素,下表描述:
- 一組
components-reconnect-*
CSS 類別(Css 類別 列),由 Blazor 在具有id
components-reconnect-modal
的元素上設定或取消設定。 - 表示重新連線狀態變更的
components-reconnect-state-changed
事件(事件 欄)。
CSS 類別 | 事件 | 表示… |
---|---|---|
components-reconnect-show |
show |
遺失的連線。 用戶端嘗試重新連線。 重新連線模式會顯示。 |
components-reconnect-hide |
hide |
重新建立與伺服器的主動連接。 重新連線模型已關閉。 |
components-reconnect-retrying |
retrying |
用戶端嘗試重新連線。 |
components-reconnect-failed |
failed |
重新連線失敗,可能是因為網路故障。 |
components-reconnect-rejected |
rejected |
拒絕重新連線。 |
當 #D0 中的重新連線狀態變更為 #B1 時,請在 JavaScript 中呼叫 #D2 以嘗試重新連線。
當重新連線狀態變更為rejected
時,伺服器已被聯繫但拒絕連接,且用戶在伺服器上的狀態已遺失。 若要重新載入應用程式,請在 JavaScript 中呼叫 location.reload()
。 出現以下情況時,可能會導致此連線狀態:
- 伺服器端線路發生當機。
- 用戶端中斷連線的時間長到足以讓伺服器移除使用者的狀態。 使用者元件的執行個體已被處置。
- 伺服器已重新啟動,或應用程式的工作程序被回收。
開發人員會在重新連線模式元素上新增事件接聽程式,以監視並回應重新連線狀態變更,如下列範例所示:
const reconnectModal = document.getElementById("components-reconnect-modal");
reconnectModal.addEventListener("components-reconnect-state-changed",
handleReconnectStateChanged);
function handleReconnectStateChanged(event) {
if (event.detail.state === "show") {
reconnectModal.showModal();
} else if (event.detail.state === "hide") {
reconnectModal.close();
} else if (event.detail.state === "failed") {
Blazor.reconnect();
} else if (event.detail.state === "rejected") {
location.reload();
}
}
具有 id
值為 components-reconnect-max-retries
的元素會顯示最大重新連線重試次數:
<span id="components-reconnect-max-retries"></span>
具有 id
components-reconnect-current-attempt
的元素會顯示目前的重新連線嘗試:
<span id="components-reconnect-current-attempt"></span>
具有id
components-seconds-to-next-attempt
的元素會顯示到下一次重新連線嘗試的秒數:
<span id="components-seconds-to-next-attempt"></span>
#D0 專案模板包含 #D1 元件(#A2),其中包含並置的樣式表和 JavaScript 檔案(#A3,#B4),可以根據需要進行自定義。 您可以在 ASP.NET Core 參考來源中查看這些檔案,或查看從 Blazor Web App 專案模板建立的應用程式。 在 Visual Studio 中建立具有互動式轉譯模式的專案時,如果將模式設定為 Server 或 Auto,該元件則會新增至專案;或者,如果使用 .NET CLI 並選擇預設或其他選項建立專案,元件也會新增至專案。
-
ReconnectModal
元件 - 樣式表檔案
- JavaScript 檔案
注意
.NET 參考來源的文件連結通常會載入存放庫的預設分支,這表示下一版 .NET 的目前開發。 若要選取特定版本的標籤,請使用 [切換分支或標籤] 下拉式清單。 如需詳細資訊,請參閱如何選取 ASP.NET Core 原始程式碼 (dotnet/AspNetCore.Docs #26205) 的版本標籤。
若要自訂 UI,請在id
元素內容中定義一個包含components-reconnect-modal
<body>
的單一元素。 下列範例將該元素放在 App
元件中。
App.razor
:
若要自訂 UI,請在id
元素內容中定義一個包含components-reconnect-modal
<body>
的單一元素。 下列範例將元素放在主機頁面中。
Pages/_Host.cshtml
:
若要自訂 UI,請在id
元素內容中定義一個包含components-reconnect-modal
<body>
的單一元素。 下列範例將元素放在版面配置頁面中。
Pages/_Layout.cshtml
:
若要自訂 UI,請在id
元素內容中定義一個包含components-reconnect-modal
<body>
的單一元素。 下列範例將元素放在主機頁面中。
Pages/_Host.cshtml
:
<div id="components-reconnect-modal">
Connection lost.<br>Attempting to reconnect...
</div>
注意
如果應用程式轉譯了多個具有 id
為 components-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;
background-color: white;
padding: 2rem;
border-radius: 0.5rem;
text-align: center;
box-shadow: 0 3px 6px 2px rgba(0, 0, 0, 0.3);
margin: 50px 50px;
position: fixed;
top: 0;
z-index: 10001;
}
下表描述了 components-reconnect-modal
架構套用至 Blazor 元素的 CSS 類別。
CSS 類別 | 表示… |
---|---|
components-reconnect-show |
遺失的連線。 用戶端嘗試重新連線。 顯示模式。 |
components-reconnect-hide |
重新建立與伺服器的主動連接。 隱藏模式。 |
components-reconnect-failed |
重新連線失敗,可能是因為網路故障。 若要嘗試重新連線,請在 JavaScript 中呼叫 window.Blazor.reconnect() 。 |
components-reconnect-rejected |
拒絕重新連線。 已連線到伺服器,但伺服器拒絕了連線,且伺服器上的使用者狀態遺失。 若要重新載入應用程式,請在 JavaScript 中呼叫 location.reload() 。 出現以下情況時,可能會導致此連線狀態:
|
透過在網站的 CSS 中為模式元素設定 transition-delay
屬性,以自訂重新連線 UI 出現之前的延遲時間。 下列範例將轉換延遲從 500 毫秒 (預設值) 設定為 1,000 毫秒 (1 秒)。
wwwroot/app.css
:
wwwroot/css/site.css
:
#components-reconnect-modal {
transition: visibility 0s linear 1000ms;
}
若要顯示目前的重新連線嘗試,請定義一個元素,使其 id
為 components-reconnect-current-attempt
。 若要顯示重新連線重試次數上限,請定義一個元素,其 id
為 components-reconnect-max-retries
。 下列範例會遵循上一個範例,將這些元素放置在重新連線嘗試模式元素內。
<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>
當自定義重新連線模式出現時,它會以重新連線嘗試計數器呈現下列內容:
連線發生問題! (目前的重新連線嘗試: 1 / 8)
伺服器端轉譯
根據預設,元件會在用戶端與伺服器建立連線之前在伺服器上預先轉譯。 如需詳細資訊,請參閱預先轉譯 ASP.NET Core Razor 元件。
根據預設,元件會在用戶端與伺服器建立連線之前在伺服器上預先轉譯。 如需詳細資訊,請參閱 ASP.NET Core 中的元件標籤協助程式。
監視伺服器端線路活動
使用 CreateInboundActivityHandler 上的 CircuitHandler 方法來監視輸入線路活動。 輸入線路活動是從瀏覽器傳送至伺服器的任何活動,例如 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的SignalR檔案中設定手動啟動App.razor
的Blazor Web App線路:
設定Blazor在SignalR檔案Pages/_Host.cshtml
中的手動啟動Blazor Server線路:
設定Blazor在SignalR檔案Pages/_Layout.cshtml
中的手動啟動Blazor Server線路:
設定Blazor在SignalR檔案Pages/_Host.cshtml
中的手動啟動Blazor Server線路:
- 將
autostart="false"
屬性新增至<script>
指令碼的blazor.*.js
標記中。 - 放置一個在載入
Blazor.start()
指令碼之後呼叫 Blazor 的指令碼,並將其置於結尾</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 App ) 範例顯示了預設值的指派。
Blazor Web App:
<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 專案結構。
在元件中建立中樞連線時,請在 ServerTimeout 上設定 KeepAliveInterval (預設值:30 秒) 和 HubConnectionBuilder (預設值:15 秒)。 在已建置的 HandshakeTimeout 上設定 HubConnection (預設值: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 專案結構。
在元件中建立中樞連線時,請在建置的 ServerTimeout 中設定 HandshakeTimeout (預設值:30 秒)、KeepAliveInterval (預設值:15 秒) 和 HubConnection (預設值: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
。
必須同時指定 onConnectionDown
和 onConnectionUp
。
Blazor Web App:
<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 App:
(() => {
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 App:
<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 函數中 找到 computeDefaultRetryInterval
架構使用的預設邏輯(參考來源)。
注意
.NET 參考來源的文件連結通常會載入存放庫的預設分支,這表示下一版 .NET 的目前開發。 若要選取特定版本的標籤,請使用 [切換分支或標籤] 下拉式清單。 如需詳細資訊,請參閱如何選取 ASP.NET Core 原始程式碼 (dotnet/AspNetCore.Docs #26205) 的版本標籤。
透過指定用於計算重試間隔的函式,來自訂重試間隔行為。 在以下指數退避的範例中,將先前重新連線嘗試的次數乘以 1,000 毫秒以計算重試間隔。 當先前嘗試重新連線的次數 (previousAttempts
) 大於最大重試限制 (maxRetries
) 時,則會向重試間隔 (null
) 指派 retryIntervalMilliseconds
以停止進一步的重新連線嘗試:
Blazor.start({
circuit: {
reconnectionOptions: {
retryIntervalMilliseconds: (previousAttempts, maxRetries) =>
previousAttempts >= maxRetries ? null : previousAttempts * 1000
},
},
});
另一種方式是指定重試間隔的確切順序。 在上次指定的重試間隔之後,重試會停止,因為 retryIntervalMilliseconds
函式會傳回 undefined
:
Blazor.start({
circuit: {
reconnectionOptions: {
retryIntervalMilliseconds:
Array.prototype.at.bind([0, 1000, 2000, 5000, 10000, 15000, 30000]),
},
},
});
如需關於 Blazor 啟動的詳細資訊,請參閱 ASP.NET Core Blazor 啟動。
控制重新連線 UI 的出現時機
在下列情況中,可能會需要控制重新連線 UI 的出現時機:
- 已部署的應用程式因為網際網路延遲造成 Ping 逾時而經常顯示重新連線 UI,而您想要增加延遲閾值。
- 某個應用程式需要在更短時間內向使用者回報連線已中斷,因此您想要縮短延遲閾值。
調整用戶端上的 Keep-Alive 間隔和逾時設定會影響重新連線 UI 顯示的時機。 當用戶端收到伺服器逾時通知(withServerTimeout
,用戶端組態區段)時,將顯示重新連線使用者介面 (UI)。 不過,變更 withServerTimeout
的值需要變更下列指引中所述的其他 Keep-Alive、超時和握手設定。
以下是作為指導的一般建議:
- 用戶端和伺服器設定的保持運作間隔(Keep-Alive)應相符。
- 逾時應該至少是 Keep-Alive 間隔指派值的兩倍。
伺服器組態
設定下列內容:
- ClientTimeoutInterval(預設值:30 秒):客戶端在伺服器關閉連線之前發送訊息的時間窗口。
- HandshakeTimeout (預設值:15 秒):伺服器針對用戶端傳入交握要求逾時所採用的間隔。
- KeepAliveInterval(預設:15秒):伺服器用來向已連線客戶端發送保活訊號的間隔時間。 請注意,用戶端上也有保持運作間隔設定,該值應符合伺服器的值。
ClientTimeoutInterval 和 HandshakeTimeout 可以增加,而 KeepAliveInterval 可以維持不變。 重要的考量是,如果您變更這些數值,請確保逾時至少是 Keep-Alive 間隔的兩倍,並且伺服器和用戶端的 Keep-Alive 間隔一致。 如需詳細資訊,請參閱客戶端上的 逾時和 Keep-Alive SignalR 設定 一節。
在以下範例中:
- ClientTimeoutInterval 會增加到 60 秒 (預設值:30 秒)。
- HandshakeTimeout 會增加到 30 秒 (預設值:15 秒)。
- KeepAliveInterval 未在開發人員程式代碼中設定 ,並使用其預設值 15 秒。 減少保持運作間隔的值會增加通訊 Ping 的頻率,從而增加應用程式、伺服器和網路上的負載。 務必小心,以免在降低 Keep-Alive 時間間隔時導致效能不佳。
Blazor Web App(.NET 8 或更新版本)在伺服器專案的 Program
檔案中:
builder.Services.AddRazorComponents().AddInteractiveServerComponents()
.AddHubOptions(options =>
{
options.ClientTimeoutInterval = TimeSpan.FromSeconds(60);
options.HandshakeTimeout = TimeSpan.FromSeconds(30);
});
Blazor Server 檔案中的 Program
:
builder.Services.AddServerSideBlazor()
.AddHubOptions(options =>
{
options.ClientTimeoutInterval = TimeSpan.FromSeconds(60);
options.HandshakeTimeout = TimeSpan.FromSeconds(30);
});
如需詳細資訊,請參閱伺服器端線路處理常式選項一節。
用戶端組態
設定下列內容:
-
withServerTimeout
(預設值:30 秒):為線路中樞連線設定以毫秒為單位的伺服器逾時。 -
withKeepAliveInterval
(預設值:15 秒):連線傳送保持運作訊息的間隔,以毫秒為單位。
伺服器的逾時時間可以延長,而 Keep-Alive 連線間隔可以保持不變。 重要的考量是,如果您變更該值,請確定伺服器逾時至少是保持運作間隔值的兩倍,且伺服器和用戶端的保持運作間隔值相符。 如需詳細資訊,請參閱在用戶端上設定 SignalR 逾時和 Keep-Alive 一節。
在下列啟動設定範例 (Blazor 指令碼的位置) 中,伺服器逾時會使用 60 秒的自訂值。 保持運作間隔 (withKeepAliveInterval
) 未設定,並使用其預設值 15 秒。
Blazor Web App:
<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>
在元件中建立中樞連線時,請在 WithServerTimeout 上設定伺服器逾時 (HubConnectionBuilder,預設值:30 秒)。 在已建置的 HandshakeTimeout 上設定 HubConnection (預設值:15 秒)。 確認逾時時間至少是持續連線間隔 (WithKeepAliveInterval/KeepAliveInterval) 的兩倍,且持續連線值在伺服器和用戶端之間相符。
下列範例是以Index
元件為基礎,來自SignalR與Blazor教程。 伺服器逾時值會增加到 60 秒,交握逾時值則會增加到 30 秒。 保持運作(Keep-Alive)間隔未設定,預設為 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 秒):連線傳送保持運作訊息的間隔,以毫秒為單位。
伺服器逾時可以增加,而 Keep-Alive 間隔可以維持不變。 重要的考量是,如果您變更該值,請確定伺服器逾時至少是保持運作間隔值的兩倍,且伺服器和用戶端的保持運作間隔值相符。 如需詳細資訊,請參閱用戶端上的 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>
在元件中建立中樞連線時,請在組建 ServerTimeout 上設定 HandshakeTimeout (預設值:30 秒) 和 HubConnection (預設值:15 秒)。 確認逾時設定至少是 Keep-Alive 間隔的兩倍。 確認伺服器與用戶端之間的 Keep-Alive 週期是否一致。
下列範例是以Index
元件為基礎,來自SignalR與Blazor教程。
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線路連線SignalR
Blazor的SignalR電路會中斷連線,當觸發unload
頁面事件時。 若要中斷用戶端上其他案例的線路連線,請在適當的事件處理常式中叫用 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.ConfigureServices
的 Startup.cs
中:
services.AddSingleton<CircuitHandler, TrackingCircuitHandler>();
如果自訂線路處理常式的方法擲回未處理的例外狀況,則此例外狀況會導致線路產生嚴重錯誤。 若要允許處理程式碼或呼叫方法中的例外狀況,請將程式碼包裝在一個或多個包含錯誤處理和記錄功能的 try-catch
陳述式中。
當線路因使用者已中斷連線而結束,且架構正在清除線路狀態時,架構會處置線路的 DI 範圍。 處置範圍時,會一併處置任何實作 System.IDisposable 的回路範圍 DI 服務。 如果任何 DI 服務在處置期間擲回未處理的例外狀況,架構會記錄例外狀況。 如需詳細資訊,請參閱 ASP.NET Core Blazor 相依性插入。
用於為自訂服務擷取使用者的伺服器端處理程序
使用 CircuitHandler 從 AuthenticationStateProvider 擷取使用者,並在服務中設定該使用者。 如需詳細資訊和範例程式代碼,請參閱 ASP.NET Core 伺服器端和其他 Blazor Web App 安全性案例。
沒有剩餘的互動式伺服器元件時關閉線路
互動式伺服器元件會使用與瀏覽器的即時連線來處理 Web UI 事件,稱為線路。 當轉譯根互動式伺服器元件時,會建立線路及其相關聯的狀態。 當頁面上沒有剩餘的互動式伺服器元件時,線路會關閉並釋放伺服器資源。
在不同的 URL 啟動 SignalR 線路
將 Blazor.start
手動建立線路 URL。 下列範例使用路徑 /signalr
。
Blazor Web App:
- <script src="_framework/blazor.web.js"></script>
+ <script src="_framework/blazor.web.js" autostart="false"></script>
+ <script>
+ Blazor.start({
+ circuit: {
+ configureSignalR: builder => builder.withUrl("/signalr")
+ },
+ });
+ </script>
Blazor Server:
- <script src="_framework/blazor.server.js"></script>
+ <script src="_framework/blazor.server.js" autostart="false"></script>
+ <script>
+ Blazor.start({
+ configureSignalR: builder => builder.withUrl("/signalr")
+ });
+ </script>
在伺服器應用程式的 MapBlazorHub 檔案中,將具有中樞路徑的下列 Program
呼叫新增到中間件處理管線中。
Blazor Web App:
app.MapBlazorHub("/signalr");
Blazor Server:
將現有呼叫保留至 檔案中的 MapBlazorHub,並使用路徑將新的呼叫新增至 MapBlazorHub:
app.MapBlazorHub();
+ app.MapBlazorHub("/signalr");
Windows 驗證的模擬身份
已驗證的中樞連線 (HubConnection) 會以 UseDefaultCredentials 建立,以指出使用 HTTP 要求的默認認證。 如需詳細資訊,請參閱 ASP.NET Core SignalR中的驗證和授權。
當應用程式以 Windows 驗證下的登入使用者身分在 IIS Express 中執行時,可能是使用者的個人或工作帳戶,默認認證就是登入用戶的認證。
當應用程式發佈至 IIS 時,應用程式會在 應用程式集區底下執行,Identity。 HubConnection 連線時使用的是裝載應用程式的 IIS「使用者」帳戶,而不是存取頁面的訪客使用者。
使用 實作模擬功能,以使用瀏覽用戶的身分識別。
在以下範例中:
- 從驗證狀態提供者取得的使用者會被轉型為 WindowsIdentity。
- 身分識別的存取令牌會隨著負責建置和啟動 WindowsIdentity.RunImpersonatedAsync的程式碼一起傳遞至 HubConnection。
protected override async Task OnInitializedAsync()
{
var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
if (authState?.User.Identity is not null)
{
var user = authState.User.Identity as WindowsIdentity;
if (user is not null)
{
await WindowsIdentity.RunImpersonatedAsync(user.AccessToken,
async () =>
{
hubConnection = new HubConnectionBuilder()
.WithUrl(NavManager.ToAbsoluteUri("/hub"), config =>
{
config.UseDefaultCredentials = true;
})
.WithAutomaticReconnect()
.Build();
hubConnection.On<string>("name", userName =>
{
name = userName;
InvokeAsync(StateHasChanged);
});
await hubConnection.StartAsync();
});
}
}
}
在上述程式代碼中,NavManager
是 NavigationManager,AuthenticationStateProvider
是 AuthenticationStateProvider 服務實例(AuthenticationStateProvider
檔)。
其他伺服器端資源
- 伺服器端主機和部署指引:SignalR組態
- ASP.NET Core SignalR 概觀
- ASP.NET Core SignalR 組態
- 伺服器端安全性文件
- ASP.NET Core Blazor 應用程式中的 IHttpContextAccessor/HttpContext
- 伺服器端重新連線活動和元件生命週期事件
- 什麼是 Azure SignalR 服務?
- Azure SignalR 服務的效能指南
- 將 ASP.NET Core SignalR 應用程式發佈至 Azure App Service
-
Blazor 範例 GitHub 存放庫 (
dotnet/blazor-samples
) (如何下載)