Разбираем Server-Sent Events в ASP.NET Core и .NET 10. Начало
Обновления UI в реальном времени больше не являются "желательной" функцией. Большинство современных приложений ожидают потоков данных в реальном времени от сервера. В течение многих лет основным решением в экосистеме .NET был SignalR. Хотя он невероятно мощный, приятно иметь другие варианты для более простых сценариев использования.
В ASP.NET Core 10 появился собственный высокоуровневый API для событий, отправляемых сервером (SSE). Он устраняет разрыв между базовым HTTP-опросом и полнодуплексными WebSockets через SignalR.
Зачем?
SignalR — мощный инструмент, который автоматически обрабатывает WebSockets, Long Polling и SSE, обеспечивая полнодуплексный (двусторонний) канал связи. Однако это сопряжено с определёнными затратами: специфический протокол, необходимость в клиентской библиотеке и потребность в «липких сессиях» или бэкэнде (например, Redis) для масштабирования.
В отличие от SignalR, SSE:
- Однонаправленные - разработаны специально для потоковой передачи данных с сервера на клиент.
- Нативны для HTTP - это стандартный HTTP-запрос с типом содержимого text/event-stream. Никаких пользовательских протоколов.
- Поддерживают автоматическое переподключение - браузеры обрабатывают переподключения напрямую через API EventSource.
- Легковесны - нет тяжёлых клиентских библиотек или сложной логики рукопожатия.
Простейшая конечная точка SSE
Мы можем использовать новый объект Results.ServerSentEvents для возврата потока событий из любого IAsyncEnumerable<T>. Поскольку IAsyncEnumerable представляет собой поток данных, который может поступать с течением времени, сервер знает, что нужно поддерживать HTTP-соединение открытым, а не закрывать его после первого «фрагмента» данных.
Вот минимальный пример конечной точки SSE, которая передаёт информацию о размещении заказов в режиме реального времени:
app.MapGet("orders/realtime", (
ChannelReader<OrderPlacement> reader,
CancellationToken ct) =>
{
// ReadAllAsync возвращает IAsyncEnumerable
// Results.ServerSentEvents заставляет браузер держать подключение открытым
// Новые данные передаются клиенту по мере поступления из канала
return Results.ServerSentEvents(
reader.ReadAllAsync(ct),
eventType: "orders");
});Когда клиент обращается к этой конечной точке:
- Сервер отправляет заголовок
Content-Type: text/event-stream.- Соединение остается активным в состоянии ожидания данных.
- Как только приложение отправляет заказ в канал, IAsyncEnumerable возвращает этот элемент, и .NET немедленно отправляет его по открытому HTTP-каналу в браузер.
Это невероятно эффективный способ обработки «push»-уведомлений без накладных расходов, связанных с протоколом с сохранением состояния.
В этом примере используется канал. В реальном приложении у вас может быть фоновый сервис, прослушивающий очередь сообщений (например, RabbitMQ или Azure Service Bus) или канал изменений БД и отправляющий новые события в канал для обработки подключёнными клиентами.
Продолжение следует…
Источник: https://www.milanjovanovic.tech/blog/server-sent-events-in-aspnetcore-and-dotnet-10