Enviar mensagens de fora de um hub

O hub do SignalR é a abstração principal para enviar mensagens a clientes conectados ao servidor SignalR. Também é possível enviar mensagens de outros locais em seu aplicativo usando o serviço IHubContext. Este artigo explica como acessar um SignalRIHubContext para enviar notificações para clientes de fora de um hub.

Observação

O IHubContext é para enviar notificações para clientes, ele não é usado para chamar métodos no Hub.

Exibir ou fazer download do código de exemplo(como fazer download)

Como obter uma uma instância do IHubContext

No SignalR do ASP.NET Core, você pode acessar uma instância do IHubContext por meio de injeção de dependência. Você pode injetar uma instância do IHubContext em um controlador, middleware ou outro serviço de DI. Use a instância para enviar mensagens aos clientes.

Injetar uma instância do IHubContext em um controlador

Você pode injetar uma instância do IHubContext em um controlador adicionando-a ao construtor:

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

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

Com acesso a uma instância do IHubContext, chame métodos de cliente como se você estivesse no próprio hub:

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

Como obter uma instância do IHubContext no middleware

Acesse o IHubContext dentro do pipeline de middleware da seguinte maneira:

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

Observação

Quando os métodos de cliente são chamados de fora da classe Hub, não há nenhum chamador associado à invocação. Portanto, não há acesso às propriedades ConnectionId, Caller e Others .

Os aplicativos que precisam mapear um usuário para a ID de conexão e persistir esse mapeamento podem fazer um dos seguintes procedimentos:

  • Persistir o mapeamento de uma ou várias conexões como grupos. Consulte Grupos no SignalR para obter mais informações.
  • Reter informações de conexão e de usuário por meio de um serviço singleton. Para obter mais informações, consulte Injetar serviços em um hub. O serviço singleton pode usar qualquer método de armazenamento, como:
    • Armazenamento na memória em um dicionário.
    • Armazenamento externo permanente. Por exemplo, um banco de dados ou armazenamento de Tabelas do Azure usando o pacote NuGet Azure.Data.Tables.
  • Passe a ID de conexão entre clientes.

Obter uma instância do IHubContext do IHost

Acessar um IHubContext do host da Web é útil para integração com áreas fora de ASP.NET Core, por exemplo, usando estruturas de injeção de dependência de terceiros:

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

Injetar um HubContext fortemente tipado

Para injetar um HubContext fortemente tipado, verifique se o Hub herda de Hub<T>. Injete-o usando a interface IHubContext<THub, T> em vez de 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);
    }
}

Consulte Hubs fortemente tipados para obter mais informações.

Use IHubContext em código genérico

Uma instância injetada IHubContext<THub> pode ser convertida em IHubContext sem um tipo genérico Hub especificado.

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

Isso é útil quando:

  • Escrever bibliotecas que não têm uma referência ao tipo específico Hub que o aplicativo está usando.
  • Escrever código genérico e que pode ser aplicado a várias implementações de Hub diferentes

Recursos adicionais