Комментарии 9
Очень хороший материал, спасибо
я бы еще в подводные камни добавил работу с исключениями. Есть определенные нюансы при работе с AsyncEnumerable
Не подумал про это! Спасибо большое!
А какие там нюансы, вкратце?
Если вкратце, основные нюансы такие:
Асинхронный итератор не выполняется не выполняется до начала перечисления. Поэтому исключение вылетит не в момент вызова метода, а только на await foreach. Это такой небольшой и понятный нюанс но просто нужно про него помнить.
Еще yield нельзя обернуть в try/catch. Разрешён только try/finally. То есть если к примеру в середине сессии случится разрыв соедниения с базой, то поймать и обработать ошибку прямо внутри итератора вокруг выдачи элементов не получится. Ловить приходится вокруг await foreach.
Нужно не забывать помечать CancellationToken параметром [EnumeratorCancellation] иначе в методы после компиляции пропихнется не раельный токен а CancellationToken.None. В целом, забыть сложно, так как компилятор отметит этот момент в коде. Но это тоже нюанс. В примерах как раз все отмечено как надо
Это не совсем про примеры из статьи. Но есть нюанс, что finally в асинхронном итераторе отработает даже если цикл перечисления прервать. Проще всего на вот таком коде это показать:
async IAsyncEnumerable<int> ReadAsync()
{
Console.WriteLine("открыли ресурс");
try
{
for (int i = 0; i < 100; i++)
{
await Task.Delay(10);
yield return i;
}
}
finally
{
// сюда попадём даже если потребитель прервётся на середине
Console.WriteLine("закрыли ресурс");
}
}
await foreach (var x in ReadAsync())
{
Console.WriteLine(x);
if (x == 3) break; // прерываем не доходя до конца цикла из 100 итераций и думаем что код из строчки 15 не выполнится
}
// Но оказывается что код выполнится, хотя вроде цикл мы прервали посередине
Вот такой вывод получится:
открыли ресурс
0
1
2
3
закрыли ресурс <- finally всё равно отработал
// Еще интересно что фактически выполнение вот этого метода
Console.WriteLine("закрыли ресурс");
// будет вызвано в контексте вот этого метода:
await foreach (var x in ReadAsync())
{
Console.WriteLine(x);
if (x == 3) break; // прерываем не доходя до конца цикла из 100 итераций и думаем что код из строчки 15 не выполнится
}Если вам нужен стриминг данных, то самое подходящее это веб-сокеты, нет?
Да, это действительно хорошая штука, но вся прелесть в веб-сокетах, что это двухсторонняя связь! То есть вы можете гонять пакеты туда, сюда и вообще построить кучу взаимодействий на этой штуке.
Но для некоторых сценариев это абсолютный оверкилл. К примеру если вы стримите логи, то нет никакого смысла в двухсторонней связи. А чтобы настроить ws придется повозиться. Поднять SignalR чтобы у вас связь корректно работала на нескольких копиях приложения к примеру.
В общем да, веб-сокеты это топ, просто геморный и вот для описанных сценариев легче без него)

Как стримить данные в ASP.NET и как их принять