Подтвердить что ты не робот

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

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

Как предотвратить исключения из метода async исключений из приложения?

EDIT:

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

4b9b3361

Ответ 1

Когда метод 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 есть [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");
    }
}

Ответ 2

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

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

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

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