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

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

Примечание.

Он 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();
    }
});

Примечание.

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

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

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

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