如何创建C# Blazor(Server-side)全局异常处理器?(非WebAssembly)
Blazor Server 全局异常处理器实现(含文本日志写入)
Blazor Server的异常场景分为组件交互/渲染异常、SignalR电路连接异常、初始HTTP请求异常三类,以下是针对性的全局处理方案,同时实现异常日志写入文本文件。
1. 实现自定义文件日志服务
先创建一个负责写入异常日志到文本文件的服务:
public interface IFileLogger { void LogException(Exception ex, string context); } public class FileLogger : IFileLogger { private readonly string _logDir; public FileLogger() { // 日志存储目录,可根据需求调整 _logDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "BlazorLogs"); Directory.CreateDirectory(_logDir); } public void LogException(Exception ex, string context) { var logFileName = $"Error_{DateTime.Now:yyyyMMdd}.txt"; var fullPath = Path.Combine(_logDir, logFileName); var logContent = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] 场景: {context}\n异常详情:\n{ex.ToString()}\n\n"; File.AppendAllText(fullPath, logContent); } }
在Program.cs中注册这个服务:
builder.Services.AddSingleton<IFileLogger, FileLogger>();
2. 捕获组件全局异常
通过自定义ErrorBoundary组件,捕获所有组件渲染、交互时的未处理异常:
创建GlobalErrorBoundary.razor组件:
@inherits ErrorBoundary @inject IFileLogger FileLogger @ChildContent @code { protected override Task OnErrorAsync(Exception exception) { // 记录组件异常日志 FileLogger.LogException(exception, "组件渲染/交互异常"); // 自定义错误提示(可根据需求修改) ErrorContent = builder => { builder.AddMarkupContent(0, @" <div class=""alert alert-danger""> <h4>出错了</h4> <p>系统遇到未预期的错误,请稍后重试。</p> </div>"); }; return base.OnErrorAsync(exception); } }
修改App.razor,用自定义错误边界包裹整个路由:
<GlobalErrorBoundary> <Router AppAssembly="@typeof(App).Assembly"> <Found Context="routeData"> <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" /> <FocusOnNavigate RouteData="@routeData" Selector="h1" /> </Found> <NotFound> <PageTitle>未找到页面</PageTitle> <LayoutView Layout="@typeof(MainLayout)"> <p role="alert">抱歉,该地址不存在。</p> </LayoutView> </NotFound> </Router> </GlobalErrorBoundary>
3. 处理SignalR电路/连接异常
Blazor Server基于SignalR通信,电路连接异常可通过自定义CircuitHandler捕获:
public class GlobalCircuitHandler : CircuitHandler { private readonly IFileLogger _fileLogger; public GlobalCircuitHandler(IFileLogger fileLogger) { _fileLogger = fileLogger; } // 捕获连接断开异常 public override Task OnConnectionDownAsync(Circuit circuit, CancellationToken cancellationToken) { _fileLogger.LogException(new Exception("SignalR连接已断开"), "电路连接异常"); return base.OnConnectionDownAsync(circuit, cancellationToken); } // 捕获电路关闭异常 public override Task OnCircuitClosedAsync(Circuit circuit, CancellationToken cancellationToken) { _fileLogger.LogException(new Exception($"电路[{circuit.Id}]已关闭"), "电路生命周期异常"); return base.OnCircuitClosedAsync(circuit, cancellationToken); } }
在Program.cs中注册:
builder.Services.AddScoped<CircuitHandler, GlobalCircuitHandler>();
4. 捕获初始HTTP请求异常
Blazor Server首次加载是HTTP请求,这类异常可通过ASP.NET全局异常中间件处理:
在Program.cs中,app.UseRouting()之后、app.MapBlazorHub()之前添加:
app.UseExceptionHandler(errorApp => { errorApp.Run(async context => { var exceptionFeature = context.Features.Get<IExceptionHandlerPathFeature>(); if (exceptionFeature?.Error != null) { var fileLogger = context.RequestServices.GetRequiredService<IFileLogger>(); fileLogger.LogException(exceptionFeature.Error, "初始HTTP请求异常"); context.Response.StatusCode = 500; await context.Response.WriteAsync("系统初始化出错,请刷新页面重试。"); } }); });
注意事项
- 组件内的异步操作必须正确
await,否则未捕获的异步异常可能无法被ErrorBoundary捕获,建议在组件内对关键异步代码添加try-catch补充处理。 - 日志文件路径可根据部署环境调整(如生产环境可配置到特定日志目录)。
内容的提问来源于stack exchange,提问作者Jck
相关产品推荐
相关产品推荐

