Blazor 应用在组件销毁阶段偶尔会冒出莫名其妙的 JS 异常,尤其涉及复杂可视化组件时更常见。BootstrapBlazor v10.6.4 专门修了两处这类问题——DockView 开启服务器端状态持久化后销毁报错,以及 Chart 组件销毁时的脚本异常。如果你在项目中用过这两个组件,这次更新值得立刻跟进。
两个 Bug 的根因与影响
DockView:持久化状态下的销毁冲突
DockView 是 BootstrapBlazor 提供的停靠窗口布局组件,支持拖拽、嵌套、折叠等交互。开启服务器端状态持久化后,组件会在 OnAfterRenderAsync 中通过 JS Interop 调用前端脚本保存布局状态。问题出在销毁流程——当组件被移除(比如切换页面或条件渲染消失),Dispose 方法仍试图调用已经不存在的 JS 对象,导致 ObjectDisposedException 或前端脚本报错。
典型触发场景:
- 用户在 DockView 中调整布局后导航到其他页面
- 使用
@if条件渲染控制 DockView 的显示与隐藏 - Blazor Server 模式下连接断开后重新连入
Chart:销毁时引用已释放的 Canvas
Chart 组件底层依赖 Chart.js,在初始化时通过 JS Interop 创建 Chart.js 实例并绑定到 Canvas 元素。销毁时需要调用 chart.destroy() 清理。但如果 DOM 元素已被 Blazor 移除(比如组件所在容器先被清空),JS 端找不到对应的 Canvas,调用就报错。
这类问题在 Blazor Server 模式更明显——服务端 Dispose 和前端 DOM 清理的时序并不严格同步。
实际项目中的规避思路
即使你还没升级到 v10.6.4,也可以在代码层面做防御性处理:
// 在组件 Dispose 时,先检查 JS Interop 是否可用再调用
protected override async ValueTask DisposeAsync(bool disposing)
{
if (disposing)
{
try
{
// 确保 JSRuntime 还在运行,避免 ObjectDisposedException
if (JSRuntime is not null)
{
await JSRuntime.InvokeVoidAsync("yourChartDestroyMethod", elementRef);
}
}
catch (JSDisconnectedException)
{
// Blazor Server 连接断开时正常忽略
}
catch (ObjectDisposedException)
{
// 组件已销毁,跳过
}
}
}
升级到 v10.6.4 后,BootstrapBlazor 内部已经做了这类防护,你不再需要自己处理这些异常。但如果你有自定义的 JS Interop 调用,上面的模式仍然值得保留。
快速上手:在 Blazor 项目中使用 BootstrapBlazor Chart
以下是一个最小可运行的示例,展示如何在 Blazor Server 项目中引入 BootstrapBlazor 并使用 Chart 组件:
# 创建 Blazor Server 项目
dotnet new blazor -n DemoApp --interactivity server
# 进入项目目录
cd DemoApp
# 安装 BootstrapBlazor 包
dotnet add package BootstrapBlazor
修改 _Imports.razor,添加组件命名空间:
@using BootstrapBlazor.Components
修改 Program.cs,注册服务:
using BootstrapBlazor;
builder.Services.AddBootstrapBlazor();
修改 App.razor 或布局文件,引入样式和脚本(在 <head> 中加样式,在 <body> 末尾加脚本):
<!-- head 中 -->
<link href="_content/BootstrapBlazor/css/bootstrap.blazor.bundle.min.css" rel="stylesheet" />
<!-- body 末尾,在现有 script 之后 -->
<script src="_content/BootstrapBlazor/js/bootstrap.blazor.bundle.min.js"></script>
然后在任意页面使用 Chart 组件,比如 Home.razor:
@page "/"
<Chart OnInit="InitChart" />
@code {
private List<ChartDataset> datasets = new();
private Task InitChart(Chart chart)
{
var data = new[] { 65, 59, 80, 81, 56, 55, 40 };
datasets.Add(new ChartDataset()
{
Data = data,
Label = "月度数据",
BorderColor = "#4bc0c0",
BackgroundColor = "#4bc0c0"
});
var options = new ChartOptions()
{
Title = "示例柱状图",
XAxes = new List<ChartAxes>()
{
new() { Labels = new[] { "1月", "2月", "3月", "4月", "5月", "6月", "7月" } }
}
};
chart.SetData(datasets);
chart.SetOptions(options);
return Task.CompletedTask;
}
}
运行项目:
dotnet run
打开浏览器访问 https://localhost:5000,即可看到柱状图渲染结果。
升级建议
- 如果你用了 DockView + 服务器端持久化:这是必升版本,销毁报错在频繁切换页面时会反复出现,甚至可能阻塞 Blazor Server 的电路回收。
- 如果你用了 Chart 组件:同样建议升级,尤其在 Blazor Server 模式下,断线重连场景容易触发这个 Bug。
- 升级方式:直接更新包版本即可,无 API 变更:
dotnet add package BootstrapBlazor --version 10.6.4
- 如果你没用这两个组件:升级优先级不高,但顺手更新也无风险,属于纯 Bug 修复版本。
Blazor 的 JS Interop 生命周期管理一直是容易踩坑的地方,组件库在销毁阶段做好防护是基本要求。这次修复说明 BootstrapBlazor 在这方面持续在补短板,对生产环境的稳定性是个加分。