HubConnectionBuilder hubConnection;
hubConnection = new HubConnectionBuilder()
.WithUrl(new Uri(Navigation.ToAbsoluteUri("/chathub")), options =>
options.HttpMessageHandlerFactory = innerHandler =>
new IncludeRequestCredentialsMessageHandler { InnerHandler = innerHandler };
}).Build();
上面的示例将中心连接 URL 配置为绝对 URI 地址 /chathub
,这是 SignalR 与 Blazor 教程中用于 Index
组件 (Pages/Index.razor
) 的 URL。 该 URI 也可以通过字符串来设置,例如 https://signalr.example.com
,或者通过配置进行设置。 Navigation
是一个注入的 NavigationManager。
有关详细信息,请参阅 ASP.NET Core SignalR 配置。
呈现模式 (Blazor WebAssembly)
如果使用 SignalR 的 Blazor WebAssembly 应用配置为在服务器上预呈现,则预呈现会在客户端与服务器建立连接之前发生。 有关详细信息,请参阅以下文章:
ASP.NET Core 中的组件标记帮助程序
预呈现和集成 ASP.NET Core Razor 组件
Blazor WebAssembly 应用的其他资源
托管 Blazor WebAssembly:保护 SignalR 中心
托管和部署 ASP.NET Core Blazor WebAssembly
ASP.NET Core SignalR 概述
ASP.NET Core SignalR 配置
Blazor 示例 GitHub 存储库 (dotnet/blazor-samples
)
为 webfarm 托管使用粘滞会话 (Blazor Server)
Blazor Server 应用预呈现以响应第一个客户端请求,这会在服务器上创建 UI 状态。 客户端尝试创建 SignalR 连接时,“必须重新连接到同一服务器”。 使用多个后端服务器的 Blazor Server 应用应实现粘滞会话,从而建立 SignalR 连接。
未在 webfarm 中启用粘滞会话的应用引发以下错误:
blazor.server.js:1 Uncaught (in promise) 错误:由于基础连接已关闭,调用被取消。
Azure SignalR 服务 (Blazor Server)
我们建议将 Azure SignalR 服务用于 Microsoft Azure 中托管的 Blazor Server 应用。 该服务与应用的 Blazor 中心配合使用,以便将 Blazor Server 应用扩展到大量并发 SignalR 连接。 此外,SignalR 服务的全球覆盖和高性能数据中心可帮助显著减少由于地理位置造成的延迟。
可将服务的 ServerStickyMode
选项或配置值设置为 Required
,从而为 Azure SignalR 服务启用粘滞会话。 有关详细信息,请参阅托管和部署 ASP.NET Core Blazor Server。
Blazor Server 应用的线路处理程序选项
使用下表所示的 CircuitOptions 配置 Blazor Server 线路。
使用 AddServerSideBlazor 的选项委托配置 Program.cs
中的选项。 下面的示例将分配上表中显示的默认选项值。 确认 Program.cs
使用 System 命名空间 (using System;
)。
在 Program.cs
中:
builder.Services.AddServerSideBlazor(options =>
options.DetailedErrors = false;
options.DisconnectedCircuitMaxRetained = 100;
options.DisconnectedCircuitRetentionPeriod = TimeSpan.FromMinutes(3);
options.JSInteropDefaultCallTimeout = TimeSpan.FromMinutes(1);
options.MaxBufferedUnacknowledgedRenderBatches = 10;
使用 AddServerSideBlazor 的选项委托配置 Startup.ConfigureServices
中的选项。 下面的示例将分配上表中显示的默认选项值。 确认 Startup.cs
使用 System 命名空间 (using System;
)。
在 Startup.ConfigureServices
中:
services.AddServerSideBlazor(options =>
options.DetailedErrors = false;
options.DisconnectedCircuitMaxRetained = 100;
options.DisconnectedCircuitRetentionPeriod = TimeSpan.FromMinutes(3);
options.JSInteropDefaultCallTimeout = TimeSpan.FromMinutes(1);
options.MaxBufferedUnacknowledgedRenderBatches = 10;
若要配置 HubConnectionContext,请结合使用 HubConnectionContextOptions 和 AddHubOptions。 有关选项说明,请参阅 ASP.NET Core SignalR 配置。 以下示例分配默认选项值。 确认文件使用的是 System 命名空间 (using System;
)。
在 Program.cs
中:
builder.Services.AddServerSideBlazor()
.AddHubOptions(options =>
options.ClientTimeoutInterval = TimeSpan.FromSeconds(30);
options.EnableDetailedErrors = false;
options.HandshakeTimeout = TimeSpan.FromSeconds(15);
options.KeepAliveInterval = TimeSpan.FromSeconds(15);
options.MaximumParallelInvocationsPerClient = 1;
options.MaximumReceiveMessageSize = 32 * 1024;
options.StreamBufferCapacity = 10;
在 Startup.ConfigureServices
中:
services.AddServerSideBlazor()
.AddHubOptions(options =>
options.ClientTimeoutInterval = TimeSpan.FromSeconds(30);
options.EnableDetailedErrors = false;
options.HandshakeTimeout = TimeSpan.FromSeconds(15);
options.KeepAliveInterval = TimeSpan.FromSeconds(15);
options.MaximumParallelInvocationsPerClient = 1;
options.MaximumReceiveMessageSize = 32 * 1024;
options.StreamBufferCapacity = 10;
MaximumReceiveMessageSize 的默认值为 32 KB。 提高此值可能会增加拒绝服务(DoS) 攻击风险。
有关 Blazor Server 的内存模型的信息,请参阅托管和部署 ASP.NET Core Blazor Server。
Blazor 中心终结点路由配置 (Blazor Server)
在 Program.cs
中,Blazor Server 应用调用 MapBlazorHub 以将 BlazorHub 映射到应用的默认路径。 Blazor Server 脚本 (blazor.server.js
) 自动指向 MapBlazorHub 创建的终结点。
反映 UI 中的连接状态 (Blazor Server)
如果客户端检测到连接已丢失,在客户端尝试重新连接时会向用户显示默认 UI。 如果重新连接失败,则会向用户提供重试选项。
若要自定义 UI,请定义一个 id
为 components-reconnect-modal
的元素。 以下示例将元素放置在主机页中。
Pages/_Host.cshtml
:
若要自定义 UI,请定义一个 id
为 components-reconnect-modal
的元素。 以下示例将元素放置在布局页中。
Pages/_Layout.cshtml
:
若要自定义 UI,请定义一个 id
为 components-reconnect-modal
的元素。 以下示例将元素放置在主机页中。
Pages/_Host.cshtml
:
<div id="components-reconnect-modal">
There was a problem with the connection!
如果应用呈现了多个 id
为 components-reconnect-modal
的元素,则只有第一个呈现的元素会接收 CSS 类更改以显示或隐藏元素。
将以下 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-failed
重新连接失败,可能是由于网络故障引起的。 若要尝试重新连接,请在 JavaScript 中调用 window.Blazor.reconnect()
。
components-reconnect-rejected
已拒绝重新连接。 已达到服务器,但拒绝连接,服务器上的用户状态丢失。 若要重新加载应用,请在 JavaScript 中调用 location.reload()
。 当出现以下情况时,可能会导致此连接状态:- 服务器端线路发生故障。
- 客户端断开连接的时间足以使服务器删除用户的状态。 用户组件的实例已被处置。
- 服务器已重启,或者应用的工作进程被回收。
通过在站点的 CSS 中为模式元素设置 transition-delay
属性,自定义重新连接显示出现之前的延迟。 以下示例将转换延迟从 500 毫秒(默认值)设置为 1000 毫秒(1 秒)。
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>)
出现自定义重新连接模式时,它会根据前面的代码呈现如下所示的内容:
There was a problem with the connection! (Current reconnect attempt: 3 / 8)
呈现模式 (Blazor Server)
默认情况下,Blazor Server 应用会在客户端与服务器建立连接之前在服务器上预呈现用户界面。 有关详细信息,请参阅 ASP.NET Core 中的组件标记帮助程序。
监视线路活动 (Blazor Server)
使用 CircuitHandler 上的 CreateInboundActivityHandler
方法监视 Blazor Server 应用中的入站线路活动。 入站线路活动是从浏览器发送到服务器的任何活动,例如 UI 事件或 JavaScript 到 .NET 的互操作调用。
例如,可以使用线路活动处理程序来检测客户端是否处于空闲状态:
public sealed class IdleCircuitHandler : CircuitHandler, IDisposable
readonly Timer timer;
readonly ILogger logger;
public IdleCircuitHandler(IOptions<IdleCircuitOptions> options,
ILogger<IdleCircuitHandler> logger)
timer = new Timer();
timer.Interval = options.Value.IdleTimeout.TotalMilliseconds;
timer.AutoReset = false;
timer.Elapsed += CircuitIdle;
this.logger = logger;
private void CircuitIdle(object? sender, System.Timers.ElapsedEventArgs e)
logger.LogInformation("{Circuit} is idle", nameof(CircuitIdle));
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;
线路活动处理程序还提供了一种从其他非 Blazor 依赖项注入 (DI) 范围访问限定范围的 Blazor 服务的方法。 有关详细信息和示例,请参阅:
ASP.NET Core 依赖关系注入
ASP.NET Core Blazor Server 其他安全方案
Blazor 启动
在 Pages/_Host.cshtml
文件(Blazor Server,除 ASP.NET Core 6.0 外的所有版本)、Pages/_Layout.cshtml
文件(Blazor Server,ASP.NET Core 6.0)或 wwwroot/index.html
(实现了 SignalR 的托管 Blazor WebAssembly)中配置 Blazor 应用的 SignalR 线路的手动启动:
将 autostart="false"
属性添加到 blazor.{server|webassembly}.js
脚本的 <script>
标记中。
放置一个在加载 Blazor 脚本后调用 Blazor.start()
的脚本,将其置于结束的 </body>
标记内。
禁用 autostart
时,应用中不依赖该回路的任何方面都能正常工作。 例如,客户端路由正常运行。 但是,在调用 Blazor.start()
之前,依赖于该回路的任何方面不会正常运行。 如果没有已建立的回路,应用行为是不可预测的。 例如,在回路断开连接时,组件方法无法执行。
有关详细信息,包括如何在文档准备就绪时初始化 Blazor,以及如何链接到 JS Promise
,请参阅 ASP.NET Core Blazor 启动。
为客户端配置以下值:
withServerTimeout
:配置服务器超时(以毫秒为单位)。 如果此超时已过但未从服务器接收任何消息,连接将终止并出现错误。 默认超时值为 30 秒。 服务器超时应至少是分配给 Keep-Alive 间隔 (withKeepAliveInterval
) 的值的两倍。
withKeepAliveInterval
:配置保持活动间隔(ping 服务器的默认间隔,以毫秒为单位)。 使用此设置,服务器可以检测强行断开连接的情况,例如客户断开其计算机的网络连接。 此 ping 的发生频率最多与服务器 ping 的频率一样。 如果服务器每 5 秒 ping 一次,则分配的值低于 5000
(5 秒)时,将会每 5 秒 ping 一次。 默认值为 15 秒。 Keep-Alive 间隔应小于或等于分配给服务器超时 (withServerTimeout
) 的值的一半。
下面的 Pages/_Host.cshtml
文件 (Blazor Server) 或 wwwroot/index.html
(Blazor WebAssembly) 示例显示了默认值的分配:
<script src="_framework/blazor.{HOSTING MODEL}.js" autostart="false"></script>
<script>
Blazor.start({
configureSignalR: function (builder) {
builder.withServerTimeout(30000).withKeepAliveInterval(15000);
</script>
在前面的标记中,{HOSTING MODEL}
占位符是 server
(适用于 Blazor Server 应用)或 webassembly
(适用于 Blazor WebAssembly 应用)。
在组件中创建中心连接时,在 HubConnectionBuilder 上设置 ServerTimeout(默认值:30 秒)和 KeepAliveInterval(默认值:15 秒)。 在生成 HubConnection 上设置 HandshakeTimeout(默认值:15 秒)。 以下基于结合使用 Blazor 与 SignalR 教程中的 Index
组件的示例显示了默认值的分配:
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 的频率一样。 如果服务器每 5 秒 ping 一次,则分配的值低于 5000
(5 秒)时,将会每 5 秒 ping 一次。 默认值为 15 秒。 Keep-Alive 间隔应小于或等于分配给服务器超时 (serverTimeoutInMilliseconds
) 的值的一半。
下面的 Pages/_Host.cshtml
文件(Blazor Server,除 ASP.NET Core 6.0 外的所有版本)、Pages/_Layout.cshtml
文件(Blazor Server,ASP.NET Core 6.0)或 wwwroot/index.html
(Blazor WebAssembly) 示例显示了默认值的分配:
<script src="_framework/blazor.{HOSTING MODEL}.js" autostart="false"></script>
<script>
Blazor.start({
configureSignalR: function (builder) {
let c = builder.build();
c.serverTimeoutInMilliseconds = 30000;
c.keepAliveIntervalInMilliseconds = 15000;
builder.build = () => {
return c;
</script>
在前面的标记中,{HOSTING MODEL}
占位符是 server
(适用于 Blazor Server 应用)或 webassembly
(适用于 Blazor WebAssembly 应用)。
在组件中创建中心连接时,在生成的 HubConnection 上设置 ServerTimeout(默认值:30 秒)、HandshakeTimeout(默认值:15 秒)和 KeepAliveInterval(默认值:15 秒)。 以下基于结合使用 Blazor 与 SignalR 教程中的 Index
组件的示例显示了默认值的分配:
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 间隔应小于或等于分配给服务器超时的值的一半。
有关详细信息,请参阅以下文章的“全球部署和连接失败”部分:
托管和部署 ASP.NET Core Blazor Server
托管和部署 ASP.NET Core Blazor WebAssembly
修改重新连接处理程序 (Blazor Server)
可以针对自定义行为修改重新连接处理程序的线路连接事件,如:
在连接断开时通知用户。
在线路连接时(通过客户端)执行日志记录。
若要修改连接事件,请为以下连接更改注册回调:
使用 onConnectionDown
删除的连接。
已建立/重新建立的连接使用 onConnectionUp
。
必须同时指定 onConnectionDown
和 onConnectionUp
。
Pages/_Host.cshtml
:
Pages/_Layout.cshtml
:
Pages/_Host.cshtml
:
<script src="_framework/blazor.server.js" autostart="false"></script>
<script>
Blazor.start({
reconnectionHandler: {
onConnectionDown: (options, error) => console.error(error),
onConnectionUp: () => console.log("Up, up, and away!")
</script>
</body>
重新连接失败后自动刷新页面 (Blazor Server)
默认的重新连接行为需要用户在重新连接失败后手动刷新页面。 但可使用自定义重新连接处理程序自动刷新页面:
Pages/_Host.cshtml
:
<div id="reconnect-modal" style="display: none;"></div>
<script src="_framework/blazor.server.js" autostart="false"></script>
<script src="boot.js"></script>
</body>
wwwroot/boot.js
:
(() => {
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 启动。
调整重新连接重试计数和间隔 (Blazor Server)
若要调整重新连接重试次数和间隔,请设置重试次数 (maxRetries
) 和允许每次重试运行的毫秒数 (retryIntervalMilliseconds
)。
Pages/_Host.cshtml
:
Pages/_Layout.cshtml
:
Pages/_Host.cshtml
:
<script src="_framework/blazor.server.js" autostart="false"></script>
<script>
Blazor.start({
reconnectionOptions: {
maxRetries: 3,
retryIntervalMilliseconds: 2000
</script>
</body>
有关 Blazor 启动的详细信息,请参阅 ASP.NET Core Blazor 启动。
从客户端断开 Blazor 线路连接 (Blazor Server)
默认情况下,触发 unload
页面事件时,Blazor 线路会断开连接。 若要断开客户端上其他方案的线路连接,请在相应的事件处理程序中调用 Blazor.disconnect
。 在下面的示例中,当页面隐藏(pagehide
事件)时,线路会断开连接:
window.addEventListener('pagehide', () => {
Blazor.disconnect();
有关 Blazor 启动的详细信息,请参阅 ASP.NET Core Blazor 启动。
Blazor Server 线路处理程序
Blazor Server 允许代码定义线路处理程序,后者允许在用户线路的状态发生更改时运行代码。 线路处理程序通过从 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.cs
中:
builder.Services.AddSingleton<CircuitHandler, TrackingCircuitHandler>();
在 Startup.cs
的 Startup.ConfigureServices
中:
services.AddSingleton<CircuitHandler, TrackingCircuitHandler>();
如果自定义线路处理程序的方法引发未处理异常,则该异常会导致 Blazor Server 线路产生严重错误。 若要容忍处理程序代码或被调用方法中的异常,请使用错误处理和日志记录将代码包装到一个或多个 try-catch
语句中。
当线路因用户断开连接而结束且框架正在清除线路状态时,框架会处置线路的 DI 范围。 处置范围时会处置所有实现 System.IDisposable 的区分线路范围的 DI 服务。 如果有任何 DI 服务在处置期间引发未处理异常,则框架会记录该异常。 有关详细信息,请参阅 ASP.NET Core Blazor 依赖项注入。
针对自定义服务用于捕获用户的 Blazor Server 线路处理程序
使用 CircuitHandler 从 AuthenticationStateProvider 捕获用户,并在服务中设置此用户。 有关详细信息和示例代码,请参阅 ASP.NET Core Blazor Server 其他安全方案。
避免在 Razor 组件中使用 IHttpContextAccessor
/HttpContext
请勿在 Blazor Server 应用的 Razor 组件中直接或间接使用 IHttpContextAccessor/HttpContext。 Blazor 应用在 ASP.NET Core 管道上下文之外运行。 既不保证 HttpContext 在 IHttpContextAccessor 中可用,也不保证 HttpContext 会保留启动了 Blazor 应用的上下文。
建议在 Blazor 应用的初始呈现期间通过根组件参数将请求状态传递给此应用。 或者,应用可以将数据复制到根组件的初始化生命周期事件中的作用域内服务中,以便在整个应用中使用。 有关详细信息,请参阅 ASP.NET Core Blazor Server 其他安全方案。
Blazor Server 安全性的一个关键方面是,连接到给定线路的用户可能会在建立 Blazor 线路后的某个时间点得到更新,但不会更新 IHttpContextAccessor。 有关使用自定义服务应对此情况的详细信息,请参阅 ASP.NET Core Blazor Server 其他安全方案。
Blazor Server 应用的其他资源
Blazor Server 托管和部署指南:SignalR 配置
ASP.NET Core SignalR 概述
ASP.NET Core SignalR 配置
Blazor Server 安全文档