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