如何捕获Blazor MAUI Hybrid中所有未处理异常(含DisposeAsync异常)
Blazor MAUI Hybrid 全局未处理异常完整捕获方案
针对你遇到的ErrorBoundary无法捕获组件DisposeAsync异常的问题,以下是适配Blazor MAUI Hybrid的多层级捕获方案:
1. MAUI 平台级全局异常捕获
MAUI提供了跨平台及平台特定的异常捕获入口,能覆盖未被Blazor层处理的异步异常(包括DisposeAsync抛出的异常):
- 在
App.xaml.cs中注册全局事件:
public App() { InitializeComponent(); // 捕获AppDomain未处理异常 AppDomain.CurrentDomain.UnhandledException += (sender, args) => { var ex = args.ExceptionObject as Exception; UploadCrashLog(ex); // 替换为你的崩溃日志上传逻辑 }; // 捕获未被观察到的Task异常(异步操作最常见的漏捕场景) TaskScheduler.UnobservedTaskException += (sender, args) => { UploadCrashLog(args.Exception); args.SetObserved(); // 标记为已处理,避免触发系统崩溃提示 }; }
- 平台补充捕获:
- Android:在
MainActivity.cs的OnCreate方法中添加:AndroidEnvironment.UnhandledExceptionRaiser += (sender, args) => { UploadCrashLog(args.Exception); args.Handled = true; }; - iOS:在
AppDelegate.cs的FinishedLaunching方法中添加:NSExceptionHandler.DefaultExceptionHandler = (exception) => { UploadCrashLog(new Exception(exception.Reason, new System.Exception(exception.CallStackSymbols))); return true; };
- Android:在
2. Blazor 组件异步释放异常兜底
为避免组件DisposeAsync直接抛出异常,创建通用安全基类统一处理:
public class SafeDisposableComponent : ComponentBase, IAsyncDisposable { public async ValueTask DisposeAsync() { try { await OnDisposeAsync(); } catch (Exception ex) { UploadCrashLog(ex); } finally { GC.SuppressFinalize(this); } } // 让业务组件重写这个方法实现异步释放逻辑 protected virtual ValueTask OnDisposeAsync() => ValueTask.CompletedTask; }
所有需要异步释放的组件继承该基类,重写OnDisposeAsync而非直接实现IAsyncDisposable,确保异常被拦截。
3. 增强 Blazor ErrorBoundary 覆盖范围
自定义ErrorBoundary扩展默认逻辑,确保组件树内的同步/异步异常都被捕获:
public class GlobalErrorBoundary : ErrorBoundary { protected override Task OnErrorAsync(Exception exception) { UploadCrashLog(exception); return base.OnErrorAsync(exception); } }
然后用这个自定义边界包裹根组件(如Main.razor):
<GlobalErrorBoundary> <ChildContent> <!-- 你的应用根内容 --> </ChildContent> <ErrorContent> <p>应用出现异常,已记录日志</p> </ErrorContent> </GlobalErrorBoundary>
4. 日志系统兜底捕获
配置自定义日志提供者,捕获所有日志中的异常信息:
public class CrashLogProvider : ILoggerProvider { public ILogger CreateLogger(string categoryName) => new CrashLogger(); public void Dispose() { } private class CrashLogger : ILogger { public IDisposable? BeginScope<TState>(TState state) => null; public bool IsEnabled(LogLevel logLevel) => logLevel >= LogLevel.Error; public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter) { if (exception != null) { UploadCrashLog(exception); } } } }
在MauiProgram.cs中注册该提供者:
builder.Logging.AddProvider(new CrashLogProvider());
验证方案有效性
用你提到的测试方法验证:创建继承SafeDisposableComponent的组件,在OnDisposeAsync中抛出异常,检查是否被捕获上传,且不会触发系统默认崩溃提示。
内容的提问来源于stack exchange,提问作者Moffen
相关产品推荐
相关产品推荐

