Поймать необработанные исключения из async

когда async метод, ожидаемый при выбрасывании исключения, исключение сохраняется где-то и выбрасывание его задерживается. В приложении WinForms или WPF он использует SynchronizationContext.Current постить исключениями. Однако, например, в консольном приложении, он создает исключение в пуле потоков и сбрасывает приложение.

как я могу предотвратить исключения из async способ вывести из строя заявление?

EDIT:

по-видимому, проблема, которую я описываю, заключается в том, что у меня есть void async методы. См. комментарии.

2 ответов


как я могу предотвратить исключения из асинхронного метода от приведения приложения?

следуйте этим рекомендациям:

  1. все async методы должны возвращать Task или Task<T> если они не есть вернуться void (например, обработчики событий).
  2. в какой-то момент, Вы должны await все Tasks вернулся из async методы. Единственная причина, по которой ты не хочешь этого делать, это если ты не ... дольше заботиться о результате операции (например, после ее отмены).
  3. Если вам нужно поймать исключение из async void обработчик событий, а затем поймать его в обработчике событий-точно так же, как вы сделали бы, если бы это был синхронный код.

вы можете найти меня async / await интро в должности полезно; я охватываю несколько других лучших практик там, а также.


когда 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);
        }
    }
}

на catch выше вы можете поместить логику обработки исключений.

далее на каждую нить (SynchronizationContext.Current is [ThreadStatic]) где вы хотите выполнить async методы с помощью этого механизма вы должны установить текущий контекст синхронизации:

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");
    }
}