Отправлять сообщения из-за пределов центра

Концентратор SignalR — это ключевая абстракция для отправки сообщений клиентам, подключенным к серверу SignalR. Кроме того, можно отправлять сообщения из других мест в приложении с помощью IHubContext службы. В этой статье объясняется, как получить доступ к SignalRIHubContext, чтобы отправлять уведомления клиентам вне центра.

Note

IHubContext предназначен для отправки уведомлений клиентам; он не используется для вызова методов на Hub.

Просмотреть или скачать образец кода (описание загрузки)

Получить экземпляр IHubContext

В ASP.NET Core SignalRможно получить доступ к экземпляру IHubContext с помощью внедрения зависимостей. Вы можете внедрить экземпляр IHubContext в контроллер, промежуточное ПО или другую службу DI. Используйте экземпляр для отправки сообщений клиентам.

Внедрите экземпляр IHubContext в контроллер

Вы можете внедрить экземпляр IHubContext в контроллер, добавив его в конструктор:

public class HomeController : Controller
{
    private readonly IHubContext<NotificationHub> _hubContext;

    public HomeController(IHubContext<NotificationHub> hubContext)
    {
        _hubContext = hubContext;
    }
}

Имея доступ к экземпляру IHubContext, вызывайте клиентские методы так, как если бы вы были в самом хабе:

public async Task<IActionResult> Index()
{
    await _hubContext.Clients.All.SendAsync("Notify", $"Home page loaded at: {DateTime.Now}");
    return View();
}

Получение экземпляра IHubContext в промежуточном ПО

Получите доступ к IHubContext в конвейере ПО промежуточного слоя следующим образом:

app.Use(async (context, next) =>
{
    var hubContext = context.RequestServices
                            .GetRequiredService<IHubContext<ChatHub>>();
    //...
    
    if (next != null)
    {
        await next.Invoke();
    }
});

Note

Когда клиентские методы вызываются из-за пределов Hub класса, вызывающий объект не связан с вызовом. Поэтому нет доступа к свойствам ConnectionId, Caller и Others.

Приложения, которые должны сопоставить пользователя с идентификатором подключения и сохранить это сопоставление, может выполнить одно из следующих действий:

  • Сохраняйте сопоставление отдельных или нескольких подключений в виде групп. Дополнительные сведения см. в SignalR разделе "Группы".
  • Сохраняйте сведения о подключении и пользователе через одну службу. Дополнительные сведения см. в статье "Внедрение служб в концентратор ". Служба singleton может использовать любой метод хранения, например:
    • Хранилище в оперативной памяти в виде словаря.
    • Постоянное внешнее хранилище. Например, база данных или служба хранилища таблиц Azure с использованием пакета NuGet Azure.Data.Tables.
  • Передайте идентификатор подключения между клиентами.

Получение экземпляра IHubContext из IHost

Доступ к IHubContext из веб-узла полезен для интеграции с компонентами вне ASP.NET Core, например при использовании сторонних платформ внедрения зависимостей:

    public class Program
    {
        public static void Main(string[] args)
        {
            var host = CreateHostBuilder(args).Build();
            var hubContext = host.Services.GetService(typeof(IHubContext<ChatHub>));
            host.Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder => {
                    webBuilder.UseStartup<Startup>();
                });
    }

Внедрить строго типизированный HubContext

Чтобы внедрить строго типизированный HubContext, убедитесь, что центр наследует от Hub<T>. Внедрите это через интерфейс IHubContext<THub, T>, а не IHubContext<THub>.

public class ChatController : Controller
{
    public IHubContext<ChatHub, IChatClient> _strongChatHubContext { get; }

    public ChatController(IHubContext<ChatHub, IChatClient> chatHubContext)
    {
        _strongChatHubContext = chatHubContext;
    }

    public async Task SendMessage(string user, string message)
    {
        await _strongChatHubContext.Clients.All.ReceiveMessage(user, message);
    }
}

Дополнительные сведения см. в разделе "Использование строго типизированных центров ".

Использование IHubContext в универсальном коде

Внедрённый объект IHubContext<THub> можно привести к IHubContext без указания обобщённого типа Hub.

class MyHub : Hub
{ }

class MyOtherHub : Hub
{ }

app.Use(async (context, next) =>
{
    var myHubContext = context.RequestServices
                            .GetRequiredService<IHubContext<MyHub>>();
    var myOtherHubContext = context.RequestServices
                            .GetRequiredService<IHubContext<MyOtherHub>>();
    await CommonHubContextMethod((IHubContext)myHubContext);
    await CommonHubContextMethod((IHubContext)myOtherHubContext);

    await next.Invoke();
}

async Task CommonHubContextMethod(IHubContext context)
{
    await context.Clients.All.SendAsync("clientMethod", new Args());
}

Это полезно, если:

  • Создание библиотек, которые не ссылаются на конкретный тип Hub, используемый приложением.
  • Написание кода, который является универсальным и может применяться к нескольким различным Hub реализациям

Дополнительные ресурсы