ASP.NET Core Blazor SignalR 指南

本文介绍如何配置和管理 Blazor 应用中的 SignalR 连接。

有关 ASP.NET Core SignalR 配置的常规指南,请参阅文档的 ASP.NET Core SignalR 简介 区域中的主题。 若要配置添加到托管的 Blazor WebAssembly 解决方案的 SignalR,请参阅 ASP.NET Core SignalR 配置

用于身份验证的 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 选项:

    HubConnectionBuilder hubConnecton;
    
    ...
    
    hubConnecton = new HubConnectionBuilder()
        .WithUrl(new Uri(NavigationManager.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,或者通过配置进行设置。

有关详细信息,请参阅 ASP.NET Core SignalR 配置

呈现模式

如果使用 SignalR 的 Blazor WebAssembly 应用配置为在服务器上预呈现,则预呈现会在客户端与服务器建立连接之前发生。 有关详细信息,请参阅以下文章:

其他资源

本文介绍如何配置和管理 Blazor 应用中的 SignalR 连接。

有关 ASP.NET Core SignalR 配置的常规指南,请参阅文档的 ASP.NET Core SignalR 简介 区域中的主题。 若要配置添加到托管的 Blazor WebAssembly 解决方案的 SignalR,请参阅 ASP.NET Core SignalR 配置

线路处理程序选项

使用下表所示的 CircuitOptions 配置 Blazor Server 线路。

选项 默认 描述
DetailedErrors false 当线路上发生未经处理的异常时,或者通过 JS 互操作的 .NET 方法调用导致异常时,便向 JavaScript 发送详细的异常消息。
DisconnectedCircuitMaxRetained 100 服务器在内存中一次保留的断开连接的线路数上限。
DisconnectedCircuitRetentionPeriod 3 分钟 断开连接的线路被移除前在内存中保留的最长时间。
JSInteropDefaultCallTimeout 1 分钟 服务器在使异步 JavaScript 函数调用超时之前等待的最长时间。
MaxBufferedUnacknowledgedRenderBatches 10 在给定时间内,服务器在内存中对每条线路保留用以支持重新连接可靠的未确认的呈现批处理的最大数量。 达到限制后,服务器会停止生成新的呈现批处理,直到客户端确认了一个或多个批处理。

使用 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;
});

若要配置 HubConnectionContext,请结合使用 HubConnectionContextOptionsAddHubOptions。 有关选项说明,请参阅 ASP.NET Core SignalR 配置。 以下示例分配默认选项值。 确认 Program.cs 使用 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;
    });

Blazor 中心终结点路由配置

Program.cs 中,Blazor Server 应用调用 MapBlazorHub 以将 Blazor Hub 映射到应用的默认路径。 Blazor Server 脚本 (blazor.server.js) 自动指向 MapBlazorHub 创建的终结点。

反映 UI 中的连接状态

如果客户端检测到连接已丢失,在客户端尝试重新连接时会向用户显示默认 UI。 如果重新连接失败,则会向用户提供重试选项。

若要自定义 UI,请在 _Layout.cshtml Razor 页面的 <body> 中使用 components-reconnect-modalid 定义一个元素。

Pages/_Layout.cshtml:

<div id="components-reconnect-modal">
    ...
</div>

将以下 CSS 样式添加到站点的样式表中。

wwwroot/css/site.css:

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

#components-reconnect-modal.components-reconnect-show {
    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()。 当出现以下情况时,可能会导致此连接状态:
  • 服务器端线路发生故障。
  • 客户端断开连接的时间足以使服务器删除用户的状态。 用户组件的实例已被处置。
  • 服务器已重启,或者应用的工作进程被回收。

呈现模式

默认情况下,Blazor Server 应用会在客户端与服务器建立连接之前在服务器上预呈现用户界面。 有关详细信息,请参阅 组件标记帮助程序 ASP.NET Core

Blazor 启动

Pages/_Layout.cshtml 文件中配置 Blazor Server 应用 SignalR 回路 的手动启动:

  • autostart="false" 属性添加到 blazor.server.js 脚本的 <script> 标记中。
  • 将调用 Blazor.start 的脚本放置在 blazor.server.js 脚本的 <script> 标记之后并放在结束的 </body> 标记内。

禁用 autostart 时,应用中不依赖该回路的任何方面都能正常工作。 例如,客户端路由正常运行。 但是,在调用 Blazor.start 之前,依赖于该回路的任何方面不会正常运行。 如果没有已建立的回路,应用行为是不可预测的。 例如,在回路断开连接时,组件方法无法执行。

有关详细信息,包括如何在文档准备就绪时初始化 Blazor 以及如何链接到 JS Promise,请参阅 ASP.NET Core Blazor 启动

配置 SignalR 客户端日志

在客户端生成器上,传入 configureSignalR 配置对象,该对象使用日志级别调用 configureLogging

Pages/_Layout.cshtml:

<body>
    ...

    <script src="_framework/blazor.server.js" autostart="false"></script>
    <script>
      Blazor.start({
        configureSignalR: function (builder) {
          builder.configureLogging("information");
        }
      });
    </script>
</body>

在前面的示例中,information 相当于日志级别 LogLevel.Information

有关 Blazor 启动的详细信息,请参阅 ASP.NET Core Blazor 启动

修改重新连接处理程序

可以针对自定义行为修改重新连接处理程序的线路连接事件,如:

  • 在连接断开时通知用户。
  • 在线路连接时(通过客户端)执行日志记录。

若要修改连接事件,请为以下连接更改注册回调:

  • 使用 onConnectionDown 删除的连接。
  • 已建立/重新建立的连接使用 onConnectionUp

必须同时指定 onConnectionDownonConnectionUp

Pages/_Layout.cshtml:

<body>
    ...

    <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 启动的详细信息,请参阅 ASP.NET Core Blazor 启动

调整重新连接重试计数和间隔

若要调整重新连接重试次数和间隔,请设置重试次数 (maxRetries) 和允许每次重试运行的毫秒数 (retryIntervalMilliseconds)。

Pages/_Layout.cshtml:

<body>
    ...

    <script src="_framework/blazor.server.js" autostart="false"></script>
    <script>
      Blazor.start({
        reconnectionOptions: {
          maxRetries: 3,
          retryIntervalMilliseconds: 2000
        }
      });
    </script>
</body>

有关 Blazor 启动的详细信息,请参阅 ASP.NET Core Blazor 启动

隐藏或替换重新连接显示

若要隐藏重新连接显示,请将重新连接处理程序的 _reconnectionDisplay 设置为空对象({}new Object())。

Pages/_Layout.cshtml:

<body>
    ...

    <script src="_framework/blazor.server.js" autostart="false"></script>
    <script>
      window.addEventListener('beforeunload', function () {
        Blazor.defaultReconnectionHandler._reconnectionDisplay = {};
      });

      Blazor.start();
    </script>
</body>

若要替换重新连接显示,请将前面示例中的 _reconnectionDisplay 设置为要显示的元素:

Blazor.defaultReconnectionHandler._reconnectionDisplay = 
  document.getElementById("{ELEMENT ID}");

占位符 {ELEMENT ID} 是要显示的 HTML 元素的 ID。

有关 Blazor 启动的详细信息,请参阅 ASP.NET Core Blazor 启动

通过在站点的 CSS 中为模式元素设置 transition-delay 属性,自定义重新连接显示出现之前的延迟。 以下示例将转换延迟从 500 毫秒(默认值)设置为 1000 毫秒(1 秒)。

wwwroot/css/site.css:

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

从客户端断开 Blazor 线路连接

默认情况下,触发 unload 页面事件时,Blazor 线路会断开连接。 若要断开客户端上其他方案的线路连接,请在相应的事件处理程序中调用 Blazor.disconnect。 在下面的示例中,当页面隐藏(pagehide 事件)时,线路会断开连接:

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

有关 Blazor 启动的详细信息,请参阅 ASP.NET Core Blazor 启动

Blazor Server 线路处理程序

Blazor Server 允许代码定义线路处理程序,后者允许在用户线路的状态发生更改时运行代码。 线路处理程序通过从 CircuitHandler 派生并在应用的服务容器中注册该类实现。 以下线路处理程序示例跟踪打开的 SignalR 连接。

TrackingCircuitHandler.cs:

using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
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>();

如果自定义线路处理程序的方法引发未处理异常,则该异常会导致 Blazor Server 线路产生严重错误。 若要容忍处理程序代码或被调用方法中的异常,请使用错误处理和日志记录将代码包装到一个或多个 try-catch 语句中。

当线路因用户断开连接而结束且框架正在清除线路状态时,框架会处置线路的 DI 范围。 处置范围时会处置所有实现 System.IDisposable 的区分线路范围的 DI 服务。 如果有任何 DI 服务在处置期间引发未处理异常,则框架会记录该异常。

Azure SignalR 服务

我们建议将 Azure SignalR 服务用于 Microsoft Azure 中托管的 Blazor Server 应用。 该服务与应用的 Blazor 中心配合使用,以便将 Blazor Server 应用扩展到大量并发 SignalR 连接。 此外,SignalR 服务的全球覆盖和高性能数据中心可帮助显著减少由于地理位置造成的延迟。 如需对 Azure SignalR 服务的预呈现支持,请将应用配置为使用粘滞会话。 有关详细信息,请参阅 托管和部署 ASP.NET Core Blazor Server

其他资源

本文介绍如何配置和管理 Blazor 应用中的 SignalR 连接。

有关 ASP.NET Core SignalR 配置的常规指南,请参阅文档的 ASP.NET Core SignalR 简介 区域中的主题。 若要配置添加到托管的 Blazor WebAssembly 解决方案的 SignalR,请参阅 ASP.NET Core SignalR 配置

用于身份验证的 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 选项:

    HubConnectionBuilder hubConnecton;
    
    ...
    
    hubConnecton = new HubConnectionBuilder()
        .WithUrl(new Uri(NavigationManager.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,或者通过配置进行设置。

有关详细信息,请参阅 ASP.NET Core SignalR 配置

呈现模式

如果使用 SignalR 的 Blazor WebAssembly 应用配置为在服务器上预呈现,则预呈现会在客户端与服务器建立连接之前发生。 有关详细信息,请参阅以下文章:

其他资源

本文介绍如何配置和管理 Blazor 应用中的 SignalR 连接。

有关 ASP.NET Core SignalR 配置的常规指南,请参阅文档的 ASP.NET Core SignalR 简介 区域中的主题。 若要配置添加到托管的 Blazor WebAssembly 解决方案的 SignalR,请参阅 ASP.NET Core SignalR 配置

线路处理程序选项

使用下表所示的 CircuitOptions 配置 Blazor Server 线路。

选项 默认 描述
DetailedErrors false 当线路上发生未经处理的异常时,或者通过 JS 互操作的 .NET 方法调用导致异常时,便向 JavaScript 发送详细的异常消息。
DisconnectedCircuitMaxRetained 100 服务器在内存中一次保留的断开连接的线路数上限。
DisconnectedCircuitRetentionPeriod 3 分钟 断开连接的线路被移除前在内存中保留的最长时间。
JSInteropDefaultCallTimeout 1 分钟 服务器在使异步 JavaScript 函数调用超时之前等待的最长时间。
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,请结合使用 HubConnectionContextOptionsAddHubOptions。 有关选项说明,请参阅 ASP.NET Core SignalR 配置。 以下示例分配默认选项值。 确认 Startup.cs 使用 System 命名空间 (using System;)。

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;
    });

Blazor 中心终结点路由配置

Startup.Configure 中,Blazor Server 应用对 UseEndpointsIEndpointRouteBuilder 调用 MapBlazorHub,以将 Blazor Hub 映射到应用的默认路径。 Blazor Server 脚本 (blazor.server.js) 自动指向 MapBlazorHub 创建的终结点。

反映 UI 中的连接状态

如果客户端检测到连接已丢失,在客户端尝试重新连接时会向用户显示默认 UI。 如果重新连接失败,则会向用户提供重试选项。

若要自定义 UI,请在 _Host.cshtml Razor 页面的 <body> 中使用 components-reconnect-modalid 定义一个元素。

Pages/_Host.cshtml:

<div id="components-reconnect-modal">
    ...
</div>

将以下 CSS 样式添加到站点的样式表中。

wwwroot/css/site.css:

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

#components-reconnect-modal.components-reconnect-show {
    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()。 当出现以下情况时,可能会导致此连接状态:
  • 服务器端线路发生故障。
  • 客户端断开连接的时间足以使服务器删除用户的状态。 用户组件的实例已被处置。
  • 服务器已重启,或者应用的工作进程被回收。

呈现模式

默认情况下,Blazor Server 应用会在客户端与服务器建立连接之前在服务器上预呈现用户界面。 有关详细信息,请参阅 组件标记帮助程序 ASP.NET Core

Blazor 启动

Pages/_Host.cshtml 文件中配置 Blazor Server 应用 SignalR 回路 的手动启动:

  • autostart="false" 属性添加到 blazor.server.js 脚本的 <script> 标记中。
  • 将调用 Blazor.start 的脚本放置在 blazor.server.js 脚本的 <script> 标记之后并放在结束的 </body> 标记内。

禁用 autostart 时,应用中不依赖该回路的任何方面都能正常工作。 例如,客户端路由正常运行。 但是,在调用 Blazor.start 之前,依赖于该回路的任何方面不会正常运行。 如果没有已建立的回路,应用行为是不可预测的。 例如,在回路断开连接时,组件方法无法执行。

有关详细信息,包括如何在文档准备就绪时初始化 Blazor 以及如何链接到 JS Promise,请参阅 ASP.NET Core Blazor 启动

配置 SignalR 客户端日志

在客户端生成器上,传入 configureSignalR 配置对象,该对象使用日志级别调用 configureLogging

Pages/_Host.cshtml:

<body>
    ...

    <script src="_framework/blazor.server.js" autostart="false"></script>
    <script>
      Blazor.start({
        configureSignalR: function (builder) {
          builder.configureLogging("information");
        }
      });
    </script>
</body>

在前面的示例中,information 相当于日志级别 LogLevel.Information

有关 Blazor 启动的详细信息,请参阅 ASP.NET Core Blazor 启动

修改重新连接处理程序

可以针对自定义行为修改重新连接处理程序的线路连接事件,如:

  • 在连接断开时通知用户。
  • 在线路连接时(通过客户端)执行日志记录。

若要修改连接事件,请为以下连接更改注册回调:

  • 使用 onConnectionDown 删除的连接。
  • 已建立/重新建立的连接使用 onConnectionUp

必须同时指定 onConnectionDownonConnectionUp

Pages/_Host.cshtml:

<body>
    ...

    <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 启动的详细信息,请参阅 ASP.NET Core Blazor 启动

调整重新连接重试计数和间隔

若要调整重新连接重试次数和间隔,请设置重试次数 (maxRetries) 和允许每次重试运行的毫秒数 (retryIntervalMilliseconds)。

Pages/_Host.cshtml:

<body>
    ...

    <script src="_framework/blazor.server.js" autostart="false"></script>
    <script>
      Blazor.start({
        reconnectionOptions: {
          maxRetries: 3,
          retryIntervalMilliseconds: 2000
        }
      });
    </script>
</body>

有关 Blazor 启动的详细信息,请参阅 ASP.NET Core Blazor 启动

隐藏或替换重新连接显示

若要隐藏重新连接显示,请将重新连接处理程序的 _reconnectionDisplay 设置为空对象({}new Object())。

Pages/_Host.cshtml:

<body>
    ...

    <script src="_framework/blazor.server.js" autostart="false"></script>
    <script>
      window.addEventListener('beforeunload', function () {
        Blazor.defaultReconnectionHandler._reconnectionDisplay = {};
      });

      Blazor.start();
    </script>
</body>

若要替换重新连接显示,请将前面示例中的 _reconnectionDisplay 设置为要显示的元素:

Blazor.defaultReconnectionHandler._reconnectionDisplay = 
  document.getElementById("{ELEMENT ID}");

占位符 {ELEMENT ID} 是要显示的 HTML 元素的 ID。

有关 Blazor 启动的详细信息,请参阅 ASP.NET Core Blazor 启动

通过在站点的 CSS 中为模式元素设置 transition-delay 属性,自定义重新连接显示出现之前的延迟。 以下示例将转换延迟从 500 毫秒(默认值)设置为 1000 毫秒(1 秒)。

wwwroot/css/site.css:

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

从客户端断开 Blazor 线路连接

默认情况下,触发 unload 页面事件时,Blazor 线路会断开连接。 若要断开客户端上其他方案的线路连接,请在相应的事件处理程序中调用 Blazor.disconnect。 在下面的示例中,当页面隐藏(pagehide 事件)时,线路会断开连接:

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

有关 Blazor 启动的详细信息,请参阅 ASP.NET Core Blazor 启动

Blazor Server 线路处理程序

Blazor Server 允许代码定义线路处理程序,后者允许在用户线路的状态发生更改时运行代码。 线路处理程序通过从 CircuitHandler 派生并在应用的服务容器中注册该类实现。 以下线路处理程序示例跟踪打开的 SignalR 连接。

TrackingCircuitHandler.cs:

using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
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 创建单一实例服务,因为必须跟踪所有线路的状态。

Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddSingleton<CircuitHandler, TrackingCircuitHandler>();
}

如果自定义线路处理程序的方法引发未处理异常,则该异常会导致 Blazor Server 线路产生严重错误。 若要容忍处理程序代码或被调用方法中的异常,请使用错误处理和日志记录将代码包装到一个或多个 try-catch 语句中。

当线路因用户断开连接而结束且框架正在清除线路状态时,框架会处置线路的 DI 范围。 处置范围时会处置所有实现 System.IDisposable 的区分线路范围的 DI 服务。 如果有任何 DI 服务在处置期间引发未处理异常,则框架会记录该异常。

Azure SignalR 服务

我们建议将 Azure SignalR 服务用于 Microsoft Azure 中托管的 Blazor Server 应用。 该服务与应用的 Blazor 中心配合使用,以便将 Blazor Server 应用扩展到大量并发 SignalR 连接。 此外,SignalR 服务的全球覆盖和高性能数据中心可帮助显著减少由于地理位置造成的延迟。 如需对 Azure SignalR 服务的预呈现支持,请将应用配置为使用粘滞会话。 有关详细信息,请参阅 托管和部署 ASP.NET Core Blazor Server

其他资源

本文介绍如何配置和管理 Blazor 应用中的 SignalR 连接。

有关 ASP.NET Core SignalR 配置的常规指南,请参阅文档的 ASP.NET Core SignalR 简介 区域中的主题。 若要配置添加到托管的 Blazor WebAssembly 解决方案的 SignalR,请参阅 ASP.NET Core SignalR 配置

用于身份验证的 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 选项:

    HubConnectionBuilder hubConnecton;
    
    ...
    
    hubConnecton = new HubConnectionBuilder()
        .WithUrl(new Uri(NavigationManager.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,或者通过配置进行设置。

有关详细信息,请参阅 ASP.NET Core SignalR 配置

其他资源

本文介绍如何配置和管理 Blazor 应用中的 SignalR 连接。

有关 ASP.NET Core SignalR 配置的常规指南,请参阅文档的 ASP.NET Core SignalR 简介 区域中的主题。 若要配置添加到托管的 Blazor WebAssembly 解决方案的 SignalR,请参阅 ASP.NET Core SignalR 配置

线路处理程序选项

使用下表所示的 CircuitOptions 配置 Blazor Server 线路。

选项 默认 描述
DetailedErrors false 当线路上发生未经处理的异常时,或者通过 JS 互操作的 .NET 方法调用导致异常时,便向 JavaScript 发送详细的异常消息。
DisconnectedCircuitMaxRetained 100 服务器在内存中一次保留的断开连接的线路数上限。
DisconnectedCircuitRetentionPeriod 3 分钟 断开连接的线路被移除前在内存中保留的最长时间。
JSInteropDefaultCallTimeout 1 分钟 服务器在使异步 JavaScript 函数调用超时之前等待的最长时间。
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,请结合使用 HubConnectionContextOptionsAddHubOptions。 有关选项说明,请参阅 ASP.NET Core SignalR 配置。 以下示例分配默认选项值。 确认 Startup.cs 使用 System 命名空间 (using System;)。

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;
    });

Blazor 中心终结点路由配置

Startup.Configure 中,Blazor Server 应用对 UseEndpointsIEndpointRouteBuilder 调用 MapBlazorHub,以将 Blazor Hub 映射到应用的默认路径。 Blazor Server 脚本 (blazor.server.js) 自动指向 MapBlazorHub 创建的终结点。

反映 UI 中的连接状态

如果客户端检测到连接已丢失,在客户端尝试重新连接时会向用户显示默认 UI。 如果重新连接失败,则会向用户提供重试选项。

若要自定义 UI,请在 _Host.cshtml Razor 页面的 <body> 中使用 components-reconnect-modalid 定义一个元素。

Pages/_Host.cshtml:

<div id="components-reconnect-modal">
    ...
</div>

将以下 CSS 样式添加到站点的样式表中。

wwwroot/css/site.css:

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

#components-reconnect-modal.components-reconnect-show {
    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()。 当出现以下情况时,可能会导致此连接状态:
  • 服务器端线路发生故障。
  • 客户端断开连接的时间足以使服务器删除用户的状态。 用户组件的实例已被处置。
  • 服务器已重启,或者应用的工作进程被回收。

呈现模式

默认情况下,Blazor Server 应用会在客户端与服务器建立连接之前在服务器上预呈现用户界面。 有关详细信息,请参阅 组件标记帮助程序 ASP.NET Core

Blazor 启动

Pages/_Host.cshtml 文件中配置 Blazor Server 应用 SignalR 回路 的手动启动:

  • autostart="false" 属性添加到 blazor.server.js 脚本的 <script> 标记中。
  • 将调用 Blazor.start 的脚本放置在 blazor.server.js 脚本的 <script> 标记之后并放在结束的 </body> 标记内。

禁用 autostart 时,应用中不依赖该回路的任何方面都能正常工作。 例如,客户端路由正常运行。 但是,在调用 Blazor.start 之前,依赖于该回路的任何方面不会正常运行。 如果没有已建立的回路,应用行为是不可预测的。 例如,在回路断开连接时,组件方法无法执行。

有关详细信息,包括如何在文档准备就绪时初始化 Blazor 以及如何链接到 JS Promise,请参阅 ASP.NET Core Blazor 启动

配置 SignalR 客户端日志

在客户端生成器上,传入 configureSignalR 配置对象,该对象使用日志级别调用 configureLogging

Pages/_Host.cshtml:

<body>
    ...

    <script src="_framework/blazor.server.js" autostart="false"></script>
    <script>
      Blazor.start({
        configureSignalR: function (builder) {
          builder.configureLogging("information");
        }
      });
    </script>
</body>

在前面的示例中,information 相当于日志级别 LogLevel.Information

有关 Blazor 启动的详细信息,请参阅 ASP.NET Core Blazor 启动

修改重新连接处理程序

可以针对自定义行为修改重新连接处理程序的线路连接事件,如:

  • 在连接断开时通知用户。
  • 在线路连接时(通过客户端)执行日志记录。

若要修改连接事件,请为以下连接更改注册回调:

  • 使用 onConnectionDown 删除的连接。
  • 已建立/重新建立的连接使用 onConnectionUp

必须同时指定 onConnectionDownonConnectionUp

Pages/_Host.cshtml:

<body>
    ...

    <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 启动的详细信息,请参阅 ASP.NET Core Blazor 启动

调整重新连接重试计数和间隔

若要调整重新连接重试次数和间隔,请设置重试次数 (maxRetries) 和允许每次重试运行的毫秒数 (retryIntervalMilliseconds)。

Pages/_Host.cshtml:

<body>
    ...

    <script src="_framework/blazor.server.js" autostart="false"></script>
    <script>
      Blazor.start({
        reconnectionOptions: {
          maxRetries: 3,
          retryIntervalMilliseconds: 2000
        }
      });
    </script>
</body>

有关 Blazor 启动的详细信息,请参阅 ASP.NET Core Blazor 启动

隐藏或替换重新连接显示

若要隐藏重新连接显示,请将重新连接处理程序的 _reconnectionDisplay 设置为空对象({}new Object())。

Pages/_Host.cshtml:

<body>
    ...

    <script src="_framework/blazor.server.js" autostart="false"></script>
    <script>
      window.addEventListener('beforeunload', function () {
        Blazor.defaultReconnectionHandler._reconnectionDisplay = {};
      });

      Blazor.start();
    </script>
</body>

若要替换重新连接显示,请将前面示例中的 _reconnectionDisplay 设置为要显示的元素:

Blazor.defaultReconnectionHandler._reconnectionDisplay = 
  document.getElementById("{ELEMENT ID}");

占位符 {ELEMENT ID} 是要显示的 HTML 元素的 ID。

有关 Blazor 启动的详细信息,请参阅 ASP.NET Core Blazor 启动

Blazor Server 线路处理程序

Blazor Server 允许代码定义线路处理程序,后者允许在用户线路的状态发生更改时运行代码。 线路处理程序通过从 CircuitHandler 派生并在应用的服务容器中注册该类实现。 以下线路处理程序示例跟踪打开的 SignalR 连接。

TrackingCircuitHandler.cs:

using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.Server.Circuits;

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

    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 创建单一实例服务,因为必须跟踪所有线路的状态。

Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddSingleton<CircuitHandler, TrackingCircuitHandler>();
}

如果自定义线路处理程序的方法引发未处理异常,则该异常会导致 Blazor Server 线路产生严重错误。 若要容忍处理程序代码或被调用方法中的异常,请使用错误处理和日志记录将代码包装到一个或多个 try-catch 语句中。

当线路因用户断开连接而结束且框架正在清除线路状态时,框架会处置线路的 DI 范围。 处置范围时会处置所有实现 System.IDisposable 的区分线路范围的 DI 服务。 如果有任何 DI 服务在处置期间引发未处理异常,则框架会记录该异常。

Azure SignalR 服务

我们建议将 Azure SignalR 服务用于 Microsoft Azure 中托管的 Blazor Server 应用。 该服务与应用的 Blazor 中心配合使用,以便将 Blazor Server 应用扩展到大量并发 SignalR 连接。 此外,SignalR 服务的全球覆盖和高性能数据中心可帮助显著减少由于地理位置造成的延迟。 如需对 Azure SignalR 服务的预呈现支持,请将应用配置为使用粘滞会话。 有关详细信息,请参阅 托管和部署 ASP.NET Core Blazor Server

其他资源