从异步中捕获未处理的exception

当等待的async方法抛出exception时,exception存储在某处并且抛出它会被延迟。 在WinForms或WPF应用程序中,它使用SynchronizationContext.Current来发布exception的抛出。 但是,在例如控制台应用程序中,它会在线程池上抛出exception并关闭应用程序。

如何防止async方法抛出的exception导致应用程序崩溃?

编辑:

显然,我所描述的问题是因为我有void async方法。 看评论。

如何防止异步方法抛出的exception导致应用程序崩溃?

遵循以下最佳做法:

  1. 所有async方法都应返回TaskTask除非它们必须返回void (例如,事件处理程序)。
  2. 在某些时候,您应该awaitasync方法返回的所有Task 。 您不想这样做的唯一原因是您不再关心操作的结果(例如,在您取消它之后)。
  3. 如果需要从async void事件处理程序中捕获exception,那么在事件处理程序中捕获它 – 就像在同步代码中一样。

您可能会发现我的async / await简介有用; 我还介绍了其他几个最佳实践。

启动async方法时,它会捕获当前的同步上下文。 解决此问题的方法是创建自己的同步上下文来捕获exception。

这里的要点是同步上下文将回调发布到线程池,但是有一个try / catch:

 public class AsyncSynchronizationContext : SynchronizationContext { public override void Send(SendOrPostCallback d, object state) { try { d(state); } catch (Exception ex) { // Put your exception handling logic here. Console.WriteLine(ex.Message); } } public override void Post(SendOrPostCallback d, object state) { try { d(state); } catch (Exception ex) { // Put your exception handling logic here. Console.WriteLine(ex.Message); } } } 

在上面的catch ,您可以放置​​exception处理逻辑。

接下来,在要使用此机制执行async方法的每个线程( SynchronizationContext.Current[ThreadStatic] )上,必须设置当前同步上下文:

 SynchronizationContext.SetSynchronizationContext(new AsyncSynchronizationContext()); 

完整的Main例子:

 class Program { static void Main(string[] args) { SynchronizationContext.SetSynchronizationContext(new AsyncSynchronizationContext()); ExecuteAsyncMethod(); Console.ReadKey(); } private static async void ExecuteAsyncMethod() { await AsyncMethod(); } private static async Task AsyncMethod() { throw new Exception("Exception from async"); } }