ConfigureAwait и распространение исключений
Разберитесь в захвате контекста и ConfigureAwait(false); обрабатывайте исключения с await и при блокирующих вызовах; изучите AggregateException и лучшие практики.
«ConfigureAwait и распространение исключений» — бесплатный урок C# Academy на CoddyKit. Это урок 3 из 3. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C# Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C# Academy содержит 3 уроков всего.
Контекст и исключения
Цели:
- Понять, что такое захват контекста
- Знать, когда использовать ConfigureAwait(false)
- Понять, как распространяются исключения при использовании await
- Понять, почему blocking приводит к AggregateException
Рекомендация для библиотек
Методы библиотек должны использовать ConfigureAwait(false), чтобы не возобновлять выполнение в контексте пользовательского интерфейса или веб-приложения, которым они не управляют.
using System;
using System.Threading.Tasks;
public static class NetLib
{
// Library code should not assume a UI context. Use ConfigureAwait(false).
public static async Task<string> FetchAsync()
{
await Task.Delay(100).ConfigureAwait(false); // do not capture context
return "payload";
}
}
public class Program
{
public static void Main(string[] args)
{
// Console apps typically have no SynchronizationContext; this still runs fine.
string s = NetLib.FetchAsync().GetAwaiter().GetResult();
Console.WriteLine("Got: " + s);
}
}
Правила работы с контекстом
Захват контекста:
- По умолчанию await пытается возобновить выполнение в захваченном контексте (пользовательский интерфейс или ASP.NET)
- ConfigureAwait(false) означает: не захватывать контекст, а продолжить выполнение в пуле потоков
- Это помогает избежать взаимных блокировок, когда вызывающий код блокирует поток контекста
- Коду пользовательского интерфейса может понадобиться контекст для обновления элементов управления; библиотечному коду он обычно не нужен
Await и исключения
При использовании await исключение распространяется в виде исходного типа исключения; перехватывайте его обычным способом.
using System;
using System.Threading.Tasks;
public class Program
{
static async Task<string> BoomAsync()
{
await Task.Delay(50);
throw new InvalidOperationException("boom");
}
public static void Main(string[] args)
{
// With await (inside async), exceptions rethrow as the original type.
try
{
string r = BoomAsync().GetAwaiter().GetResult(); // emulate await in Main
Console.WriteLine(r);
}
catch (InvalidOperationException ex)
{
Console.WriteLine("Caught: " + ex.GetType().Name + " - " + ex.Message);
}
}
}
Блокировка и ошибки
Блокировка с помощью .Result или .Wait() оборачивает ошибки в AggregateException; для более понятного распространения ошибок отдавайте предпочтение await.
using System;
using System.Threading.Tasks;
public class Program
{
static async Task<int> FailsAsync()
{
await Task.Delay(30);
throw new ArgumentException("bad arg");
}
public static void Main(string[] args)
{
try
{
// Blocking with .Result wraps the exception into AggregateException
int x = FailsAsync().Result;
Console.WriteLine(x);
}
catch (AggregateException ae)
{
Exception inner = ae.InnerException;
Console.WriteLine("AggregateException -> " + (inner == null ? "null" : inner.GetType().Name));
}
}
}
Рекомендации
Рекомендации:
- В библиотеках используйте ConfigureAwait(false)
- В приложениях с пользовательским интерфейсом и веб-приложениях используйте await в вызывающем потоке, когда нужен контекст
- Избегайте .Result/.Wait(); перехватывайте исходные исключения с помощью await
- При необходимости ведите журнал и повторно выбрасывайте исключения с понятными сообщениями, учитывающими контекст
Поведение ConfigureAwait
Повторение
Повторение: используйте ConfigureAwait(false) в библиотеках; код пользовательского интерфейса и веб-код сами решают, когда им нужен контекст. Отдавайте предпочтение await для понятного распространения исключений; блокировка оборачивает ошибки и создаёт риск взаимных блокировок.
Часто задаваемые вопросы
Урок «ConfigureAwait и распространение исключений» бесплатный?
Да — полный текст урока «ConfigureAwait и распространение исключений» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C# Academy, подпишись на CoddyKit PRO. Курс C# Academy содержит 3 уроков всего.
Чему я научусь в уроке «ConfigureAwait и распространение исключений»?
Разберитесь в захвате контекста и ConfigureAwait(false); обрабатывайте исключения с await и при блокирующих вызовах; изучите AggregateException и лучшие практики. Ты практикуешь C# Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать C# Academy?
Предыдущий опыт не требуется. C# Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 3.
Сколько времени занимает урок «ConfigureAwait и распространение исключений»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке C# Academy?
Да. Каждый урок C# Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Task/ValueTask и асинхронная машина состояний (концепции)
- Подводные камни асинхронности: синхронный вызов асинхронного кода и взаимные блокировки
- ConfigureAwait и распространение исключений