在 Avalonia 中实现全局异常处理需三者配合:1. 注册 AppDomain.CurrentDomain.UnhandledException 捕获主线程崩溃异常;2. 订阅 TaskScheduler.UnobservedTaskException 处理未观察的 Task 异常;3. 重写 Application.OnUnhandledException(Avalonia 11+)捕获 UI 线程框架内未处理异常,三者覆盖绝大多数场景。

在 Avalonia 中实现全局异常处理器,核心是捕获应用主线程未处理的异常(如 UI 线程中抛出但未被 try/catch 捕获的异常),以及任务异步操作中未观察到的异常。Avalonia 本身基于 .NET 运行时,因此需结合 .NET 的异常捕获机制,并在 Avalonia 生命周期关键节点进行注册。
监听 AppDomain.CurrentDomain.UnhandledException
这是捕获非托管线程或部分同步上下文中未处理异常的兜底方式,适用于大多数崩溃性异常(如 NullReferenceException 在事件处理中直接抛出)。
- 在 App.xaml.cs 的 App() 构造函数或 App.Initialize() 之前 就注册,确保尽早生效
- 该事件无法阻止应用退出,但可用于日志记录、弹窗提示或数据保存
- 注意:它不捕获 async void 方法中的异常,也不捕获 Task 异常(除非未 await 且未被 TaskScheduler.UnobservedTaskException 捕获)
订阅 TaskScheduler.UnobservedTaskException
用于捕获被丢弃(未 await、未 .Wait()、未 .Result)的 Task 中抛出的异常。这类异常默认会被静默吞掉,直到 GC 时触发此事件。
- 建议在应用启动早期(如 App.OnFrameworkInitializationCompleted 或 Program.BuildAvaloniaApp().StartWithClassicDesktopLifetime() 之后)注册
- 调用
e.SetObserved()可标记为“已处理”,避免最终触发 AppDomain.UnhandledException - 典型场景:忘记 await 一个命令执行、后台 Task.Run 内部出错但没处理
重写 Application.OnUnhandledException(Avalonia 11+ 推荐)
Avalonia 11 起提供了更贴近框架语义的入口:Application.OnUnhandledException,它会在 Avalonia 内部检测到 UI 线程未处理异常(如路由事件处理器、绑定转换器、控件生命周期方法中抛异常)时被调用。
- 继承自 Application 类,在其中重写该方法
-
OnUnhandledException传入的UnhandledExceptionEventArgs包含Exception和Handled属性 - 设置
e.Handled = true可阻止 Avalonia 默认的崩溃行为(如弹出错误对话框),自行处理(如显示友好提示、上报) - 注意:它不替代 AppDomain 或 TaskScheduler 的监听,而是补充 Avalonia 特定上下文
可选:包装 Dispatcher.UIThread.Post/Invoke 操作
对于手动调度到 UI 线程的代码(如 Dispatcher.UIThread.InvokeAsync(() => { ... })),异常不会自动冒泡到全局处理器。可封装一层安全调用:
- 定义扩展方法如
SafeInvokeAsync(this IDispatcher dispatcher, Action action) - 内部用 try/catch 包裹并转发到全局日志或提示系统
- 适合对关键 UI 更新逻辑做防御性增强,非必须但能提升健壮性
基本上就这些。三者配合使用(AppDomain + TaskScheduler + OnUnhandledException)可覆盖绝大多数未处理异常场景。不需要第三方库,纯 Avalonia + .NET 原生机制即可实现可靠捕获。









