Принципы работы 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 — стандартный концентратор.
  • Hub<T> — строго типизированный универсальный концентратор.

Пример: 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 Все подключенные клиенты для указанных пользователей.

Примеры областей

Рассмотрите следующие изображения, которые помогут вам понять, как концентратор отправляет сообщения целевым клиентам. Вы можете развернуть изображения для удобства.

  • Отправка всем

    Концентратор ASP.NET Core SignalR, который отправляет сообщение с синтаксисом Clients.All.

    Все подключенные клиенты получат это сообщение независимо от того, к какой группе они принадлежат.

  • Изолированный пользователь

    Концентратор ASP.NET Core SignalR, который отправляет сообщение с синтаксисом Clients.User.

    Один пользователь получит это сообщение независимо от того, сколько устройств он использует в настоящее время.

  • Изолированная группа

    Концентратор ASP.NET Core SignalR, который отправляет сообщение с синтаксисом Clients.Group.

    Это сообщение получают только клиенты, принадлежащие к определенной группе.

Клиенты и класс 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:

Кроме того, можно использовать API асинхронного обработчика, которые являются Func<TResult>, где TResult — это вариант 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, и запустить подключение к серверу. При переходе на страницу отслеживания заказов код должен будет присоединиться к определенной группе заказа, в которой отправляются обновления изменений. Вы подпишитесь на событие для изменения состояния заказа, а затем обработаете его соответствующим образом.