从异步中捕获未处理的异常

Pie*_*kel 21 .net c# unhandled-exception async-await

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

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

编辑:

我正在描述的问题显然是因为我有void async方法.看评论.

Ste*_*ary 20

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

遵循以下最佳做法:

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

你可能会发现我async/ await介绍的帖子很有帮助; 我还介绍了其他几个最佳实践.


Pie*_*kel 11

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

这里的要点是同步上下文将回调发布到线程池,但是它周围有一个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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

catch上面你可以把你的异常处理逻辑.

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

SynchronizationContext.SetSynchronizationContext(new AsyncSynchronizationContext());
Run Code Online (Sandbox Code Playgroud)

完整的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");
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 我很抱歉,但是我没有看到你的SynchronizationContext在线程池上发布了什么 - 只要我能看到它所做的就是它立即在调用线程上执行函数并返回. (3认同)