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 baixar código de exemplo (como baixar)
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