Поймать необработанные исключения из async
когда async метод, ожидаемый при выбрасывании исключения, исключение сохраняется где-то и выбрасывание его задерживается. В приложении WinForms или WPF он использует SynchronizationContext.Current постить исключениями. Однако, например, в консольном приложении, он создает исключение в пуле потоков и сбрасывает приложение.
как я могу предотвратить исключения из async способ вывести из строя заявление?
EDIT:
по-видимому, проблема, которую я описываю, заключается в том, что у меня есть void async методы. См. комментарии.
2 ответов
как я могу предотвратить исключения из асинхронного метода от приведения приложения?
следуйте этим рекомендациям:
- все
asyncметоды должны возвращатьTaskилиTask<T>если они не есть вернутьсяvoid(например, обработчики событий). - в какой-то момент, Вы должны
awaitвсеTasks вернулся изasyncметоды. Единственная причина, по которой ты не хочешь этого делать, это если ты не ... дольше заботиться о результате операции (например, после ее отмены). - Если вам нужно поймать исключение из
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");
}
}