Принципы работы ASP.NET Core SignalR
Серверы и класс Hub
Класс Hub
является концепцией сервера SignalR. Он определен в пространстве имен Microsoft.AspNetCore.SignalR
и является частью пакета Microsoft.AspNetCore.SignaIR NuGet. ASP.NET веб-приложения Core, предназначенные для пакета SDK для Microsoft.NET.Sdk.Web, не нужно добавлять ссылку на пакет для SignalR, так как она уже доступна в рамках общей платформы.
A Hub
предоставляется через маршрут. Маршрут https://www.contoso-pizza.com/hubs/orders
может использоваться для представления реализации OrdersHub
. Через различные API концентратора авторы могут определять методы и события.
Есть две модальности предоставления методов в концентраторе. Вы создаете подкласс следующих типов и методов записи:
Пример: Hub
.
В качестве опорной точки рассмотрим следующий объект Notification
:
namespace RealTime.Models;
public record Notification(string Text, DateTime Date);
Этот объект можно предоставлять в общий доступ при использовании клиентского пакета SDK для .NET, чтобы сервер и клиент использовали один и тот же объект. Представьте себе концентратор уведомлений:
using Microsoft.AspNetCore.SignalR;
using System;
using System.Threading.Tasks;
using RealTime.Models;
namespace ExampleServer.Hubs;
public sealed class NotificationHub : Hub
{
public Task NotifyAll(Notification notification) =>
Clients.All.SendAsync("NotificationReceived", notification);
}
В отношении различий между методами и событиями метод в предыдущей реализации концентратора имеет значение NotifyAll
, а событие — NotificationReceived
. NotificationHub
— это подкласс Hub
. Метод NotifyAll
возвращает объект Task
и принимает один Notification
параметр. Метод выражен как вызов к SendAsync
из Clients.All
, который представляет все подключенные клиенты. Событие NotificationReceived
активируется в зависимости от экземпляра notification
.
Экземпляр IHubContext
Вы запускаете события из Hub
экземпляра или из нее IHubContext
. Концентратор SignalR — это основная абстракция для отправки сообщений клиентам, подключенным к серверу SignalR. Кроме того, можно отправлять сообщения из других расположений в приложении, используя один из следующих типов:
- IHubContext<THub> — контекст, где
THub
представляет стандартный концентратор. - IHubContext<THub,T>: контекст, представляющий
THub
строго типизированный универсальный концентратор иT
представляет соответствующий тип клиента.
Внимание
IHubContext
используется для отправки уведомлений клиентам и не используется для вызова методов в Hub
.
Пример IHubContext
Учитывая предыдущую реализацию концентратора уведомлений, можно использовать IHubContext<NotificationHub>
следующим образом:
using Microsoft.AspNetCore.SignalR;
using System;
using System.Threading.Tasks;
using RealTime.Models;
namespace ExampleServer.Services;
public sealed class NotificationService(
IHubContext<NotificationHub> hubContext)
{
public Task SendNotificationAsync(Notification notification) =>
notification is not null
? hubContext.Clients.All.SendAsync("NotificationReceived", notification)
: Task.CompletedTask;
}
Предыдущий код C# использует IHubContext<NotificationHub>
для доступа к контекстному списку клиентов, предоставляя возможность рассылать уведомления. Основной hubContext
параметр конструктора, захваченный в области, используется для запуска "NotificationReceived"
события, но он не предназначен для вызова метода концентратора NotifyAll
.
Методы
Методы Hub
или Hub<T>
, как и любой другой метод C#. Они определяют тип возвращаемого значения, имя метода и параметры.
- Самым распространенным типом возвращаемого значения для метода концентратора является
Task
илиTask<TResult>
, который представляет асинхронную операцию концентратора. - Имя метода используется для вызова метода из клиентов. Его можно настроить с помощью HubMethodNameAttribute.
- Параметры являются необязательными, но в процессе их определения ожидается, что клиенты будут предоставлять соответствующие аргументы.
Методы не требуются для запуска событий, но часто они делают.
События
Клиент может подписываться на события по именам. Сервер отвечает за создание событий. Hub
, , IHubContext<THub>
Hub<T>
и события именуются и IHubContext<THub, T>
могут определять до 10 параметров. События запускаются на сервере и обрабатываются заинтересованными клиентами. Клиент считается заинтересованным, когда он подписывается на события в подключении концентратора. Клиенты могут косвенно активировать события при вызове методов концентратора, которые запускают события в результате вызова. При этом клиенты не могут активировать события напрямую, так как это задача сервера.
Области применения клиента событий
События вызываются из экземпляра IClientProxy. Интерфейсы IHubClients и IHubCallerClients реализуются из типа Clients. Есть множество способов определить область действия для конкретного экземпляра IClientProxy
. Можно ориентироваться на следующие области из свойства Hub.Clients
:
Элемент | Сведения |
---|---|
All |
Все подключенные клиенты (например, широковещание). |
AllExcept |
Все подключенные клиенты, за исключением указанных подключений (например, трансляция с фильтрацией). |
Caller |
Подключенный клиент, который инициировал метод (например, эхо). |
Client |
Указанное клиентское подключение (одно подключение). |
Clients |
Указанные клиентские подключения (несколько подключений). |
Group |
Все подключенные клиенты в указанной группе. |
GroupExcept |
Все подключенные клиенты в указанной группе, за исключением указанных соединений. |
Groups |
Все подключенные клиенты в указанной группе (несколько групп). |
Others |
Все подключенные клиенты, за исключением клиента, запустившего метод. |
OthersInGroup |
Все подключенные клиенты в указанной группе, за исключением клиента, запустившего метод. |
User |
Все подключенные клиенты для указанного пользователя (один пользователь может выполнить подключение на нескольких устройствах). |
Users |
Все подключенные клиенты для указанных пользователей. |
Примеры областей
Рассмотрите следующие изображения, которые помогут вам понять, как концентратор отправляет сообщения целевым клиентам. Вы можете развернуть изображения для удобства.
Отправка всем
Все подключенные клиенты получат это сообщение независимо от того, к какой группе они принадлежат.
Изолированный пользователь
Один пользователь получит это сообщение независимо от того, сколько устройств он использует в настоящее время.
Изолированная группа
Это сообщение получают только клиенты, принадлежащие к определенной группе.
Клиенты и класс HubConnection
Класс HubConnection
представляет собой концепцию клиента SignalR, которая представляет клиентское соединение с серверомHub
. Он определен в пространстве имен Microsoft.AspNetCore.SignalR.Client
и является частью пакета Microsoft.AspNetCore.SignaIR.Client NuGet.
Создайте HubConnection
шаблон построителя и соответствующий HubConnectionBuilder
тип. Учитывая маршрут концентратора (или System.Uri), можно создать HubConnection
. Построитель также может указать дополнительные параметры конфигурации, включая ведение журнала, требуемый протокол, перенаправление маркеров проверки подлинности и автоматическое повторное подключение, среди прочего.
API HubConnection
предоставляет функции запуска и завершения, используемые для запуска и завершения подключения с сервером. Кроме того, существует возможность потоковой передачи, вызова методов концентратораи подписки на события.
Пример создания HubConnection
Чтобы создать объект HubConnection
из клиентского пакета SDK для .NET SignalR, используйте тип HubConnectionBuilder
:
using Microsoft.AspNetCore.SignalR.Client;
using System;
using System.Threading.Tasks;
using RealTime.Models;
namespace ExampleClient;
public sealed class Consumer : IAsyncDisposable
{
private readonly string HostDomain =
Environment.GetEnvironmentVariable("HOST_DOMAIN");
private HubConnection _hubConnection;
public Consumer()
{
_hubConnection = new HubConnectionBuilder()
.WithUrl(new Uri($"{HostDomain}/hub/notifications"))
.WithAutomaticReconnect()
.Build();
}
public Task StartNotificationConnectionAsync() =>
_hubConnection.StartAsync();
public async ValueTask DisposeAsync()
{
if (_hubConnection is not null)
{
await _hubConnection.DisposeAsync();
_hubConnection = null;
}
}
}
Вызов методов концентратора
Если клиенту предоставлен экземпляр клиента HubConnection
, который успешно запущен, этот клиент может вызывать методы в концентраторе с помощью InvokeAsync или SendAsync расширений. Если метод концентратора возвращает Task<TResult>
, результат InvokeAsync<TResult>
относится к типу TResult
. Если метод концентратора возвращается Task
, результат отсутствует. Как InvokeAsync
и требуется имя метода концентратора, а SendAsync
также ноль до 10 параметров.
- InvokeAsync — вызывает метод концентратора на сервере, используя указанное имя метода и необязательные аргументы.
- SendAsync — вызывает метод концентратора на сервере, используя указанное имя метода и необязательные аргументы. Этот метод не ожидает ответа от получателя.
Пример вызова метода концентратора
При SendNotificationAsync
добавлении метода в предыдущий Consumer
класс SendNotificationAsync
делегирует _hubConnection
метод и вызывает NotifyAll
метод в концентраторе сервера в зависимости от экземпляра Notification
.
public Task SendNotificationAsync(string text) =>
_hubConnection.InvokeAsync(
"NotifyAll", new Notification(text, DateTime.UtcNow));
Обработка событий
Для обработки событий необходимо зарегистрировать обработчик в экземпляре HubConnection
. Вызовите одну из перегрузок HubConnectionExtensions.On, если вам известно имя метода концентратора и у вас есть от 0 до 8 параметров. Обработчик может удовлетворять требованиям любого из следующих вариантов Action
:
- Action
- Action<T>
- Action<T1,T2>
- Action<T1,T2,T3>
- Action<T1,T2,T3,T4>
- Action<T1,T2,T3,T4,T5>
- Action<T1,T2,T3,T4,T5,T6>
- Action<T1,T2,T3,T4,T5,T6,T7>
- Action<T1,T2,T3,T4,T5,T6,T7,T8>
Кроме того, можно использовать API асинхронного обработчика, которые являются Func<TResult>
, где TResult
— это вариант Task
:
Func<Task>
Func<T,Task>
Func<T1,T2,Task>
Func<T1,T2,T3,Task>
Func<T1,T2,T3,T4,Task>
Func<T1,T2,T3,T4,T5,Task>
Func<T1,T2,T3,T4,T5,T6,Task>
Func<T1,T2,T3,T4,T5,T6,T7,Task>
Func<T1,T2,T3,T4,T5,T6,T7,T8,Task>
Результат регистрации обработчика событий — это IDisposable
подписка. Чтобы отменить подписку обработчика, вызовите Dispose.
Пример регистрации события
Обновляя предыдущий класс Consumer
, вы регистрируетесь в событии, предоставляя обработчик и вызывая On
:
using Microsoft.AspNetCore.SignalR.Client;
using System;
using System.Threading.Tasks;
using RealTime.Models;
namespace ExampleClient;
public sealed class Consumer : IAsyncDisposable
{
private readonly string HostDomain =
Environment.GetEnvironmentVariable("HOST_DOMAIN");
private HubConnection _hubConnection;
public Consumer()
{
_hubConnection = new HubConnectionBuilder()
.WithUrl(new Uri($"{HostDomain}/hub/notifications"))
.WithAutomaticReconnect()
.Build();
_hubConnection.On<Notification>(
"NotificationReceived", OnNotificationReceivedAsync);
}
private async Task OnNotificationReceivedAsync(Notification notification)
{
// Do something meaningful with the notification.
await Task.CompletedTask;
}
// Omitted for brevity.
}
Метод OnNotificationReceivedAsync
вызывается, когда экземпляр концентратора сервера запускает событие "NotificationReceived"
.
Динамическое обновление заказов Contoso Pizza
Код сервера для веб-приложения должен иметь Hub
реализацию и предоставлять маршрут клиентам. Hub
может использовать уникальный идентификатор объекта заказа для создания группы отслеживания. Все обновления изменения состояния заказов могут передаваться в этой группе.
Код клиента также нужно обновить, чтобы указать, что приложение Contoso Pizza — это приложение Blazor WebAssembly. Можно использовать пакет SDK для JavaScript или клиентский пакет SDK для .NET. Затем нужно заменить функцию опроса на стороне клиента кодом, который создает HubConnection
, и запустить подключение к серверу. При переходе на страницу отслеживания заказов код должен будет присоединиться к определенной группе заказа, в которой отправляются обновления изменений. Вы подпишитесь на событие для изменения состояния заказа, а затем обработаете его соответствующим образом.