Blazor Server应用:除现有异常捕获方式外,还有其他捕获途径吗?
在我的Blazor Server应用中,我几乎在所有框架调用的方法中都添加了try/catch(仅排除如设置bool值的OnChanged这类简单方法)。同时,我在MainLayout.razor中使用<ErrorBoundary>包裹了所有内容(代码如下)。请问这样是否能捕获所有抛出的异常?还是需要额外操作来捕获其他异常?
<ErrorBoundary> <ChildContent> <div style="height: 100%; overflow-y: hidden;"> <div style="margin: 0; height: 100%; overflow-y: hidden;"> <div style="display: flex; flex-direction: column; height: 100%; overflow-y: hidden;"> <div style="width: 100%;"> <header> <Banner ShowBanner="@SessionData.ShowWelcomeBanner" OnBannerClosed="WelcomeBannerClosed" BannerContent="Please complete your registration. <a href='/Account/Welcome'>Click here for more information.</a>" /> </header> </div> <div style="width: 100%;"> <NavMenu /> </div> <div style="flex-grow: 1; width: 100%; overflow: auto;"> <div style="height: 100%; overflow: auto;"> <main> <div class="my-main-scrollbar"> <PopupMessageBox> @Body </PopupMessageBox> </div> </main> </div> </div> <div style="width: 100%;"> <footer class="main-footer"> <span>© David Thielen 2023 - ALL RIGHTS RESERVED</span> </footer> </div> </div> </div> </div> </ChildContent> <ErrorContent Context="error"> @{ var guid = Guid.NewGuid().ToString(); var useFallback = true; if (error.Data.Contains("Category")) { var data = error.Data["Category"]; if (data is Type category) { var logger = LoggerFactory.CreateLogger(category); logger.LogError(error, "Error: {guid}", guid); useFallback = false; } } if (useFallback) { Logger.LogError(error, "Error: {guid}", guid); } } <h1>Unexpected Error (sorry)</h1> <p> The program has encountered an unexpected error (yes there are expected errors). This error has been logged and we will look at it. </p> <p>We suggest you <a href="/identity/account/LogOut">logout</a> and then log back in if you wish to try again.</p> <p>If you want to contact us, please include the following error id: @guid when you do.</p> </ErrorContent> </ErrorBoundary>
你当前的配置能覆盖大部分常规业务异常,但无法捕获所有场景,以下是具体分析和需要补充的操作:
已覆盖的异常场景
- 组件生命周期方法(如
OnInitializedAsync、OnParametersSetAsync)中未被内部try/catch处理的异常 - 组件渲染过程(包括
@Body加载的页面组件)中的同步/异步异常 - 绑定事件处理方法(如按钮点击、表单提交)中未被捕获的异常
无法自动捕获的异常场景及处理方案
后台异步任务异常
比如用Task.Run、Timer或独立启动的异步任务抛出的异常,这类任务脱离了Blazor的渲染上下文,顶层ErrorBoundary无法捕获。需要在任务内部添加try/catch,或者通过IHostedService的机制统一处理后台任务异常。SignalR通信异常
Blazor Server依赖SignalR维持客户端与服务器的连接,连接断开、重连失败等底层通信异常,ErrorBoundary无法感知。需要自定义CircuitHandler,重写OnCircuitClosedAsync、OnConnectionDownAsync等方法来监听并处理这类异常。全局启动/初始化异常
应用启动时的配置错误、DI容器初始化异常,或者跨组件的全局未处理异常,需要在Program.cs中补充全局异常处理:// 处理非Blazor路由的HTTP异常 app.UseExceptionHandler("/Error"); // 注册自定义ErrorBoundary日志器,统一处理ErrorBoundary捕获的异常 builder.Services.AddScoped<IErrorBoundaryLogger, CustomErrorBoundaryLogger>();JavaScript互操作异常
.NET调用JS方法或JS调用.NET方法时抛出的异常,需要在互操作代码处添加try/catch,或者在JS侧处理异常后通知.NET端。身份认证/授权异常
访问无权限页面时的授权异常,默认会跳转到登录页,若需自定义处理逻辑,要在身份认证中间件中配置,或在组件内的授权逻辑里捕获处理。
优化建议
- 无需在所有框架方法中添加try/catch,过度捕获会掩盖真实问题。仅在需要处理特定业务异常的地方添加try/catch,让顶层
ErrorBoundary处理未预期的全局异常。 - 可以给
ErrorBoundary添加@ref引用,在错误页面提供"重试"按钮,调用errorBoundary.Reset()方法让组件恢复渲染,提升用户体验。 - 对于预期内的业务异常(如表单验证失败、API返回错误),不要抛出异常,而是通过组件内的状态提示用户,避免触发全局错误页面。
内容的提问来源于stack exchange,提问作者David Thielen

