Envío de mensajes desde fuera de un centro de conectividad

El centro de SignalR es la abstracción básica para enviar mensajes a los clientes conectados al servidor de SignalR. También es posible enviar mensajes desde otros lugares de la aplicación mediante el servicio IHubContext. En este artículo se explica cómo acceder a SignalRIHubContext para enviar notificaciones a los clientes desde fuera de un centro.

Nota:

El objeto IHubContext es para enviar notificaciones a los clientes y no se usa para llamar a métodos en el objeto Hub.

Vea o descargue el código de ejemplo(cómo descargarlo):

Obtención de una instancia de IHubContext

En SignalR de ASP.NET Core, es posible acceder a una instancia de IHubContext a través de la inserción de dependencias. Es posible insertar una instancia de IHubContext en un controlador, middleware u otro servicio de DI. Use la instancia para enviar mensajes a los clientes.

Insertar una instancia de IHubContext en un controlador

Es posible insertar una instancia de IHubContext en un controlador agregándola al constructor:

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

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

Con el acceso a una instancia de IHubContext, puede llamar a los métodos de cliente como si estuviera en el propio centro:

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

Obtención de una instancia de IHubContext en middleware

Acceda a IHubContext dentro de la canalización de middleware de la siguiente manera:

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

Nota

Cuando se llama a los métodos de cliente desde fuera de la clase Hub, no hay ningún autor de llamada asociado a la invocación. Por lo tanto, no hay acceso a las propiedades ConnectionId, Caller y Others.

Las aplicaciones que necesiten asignar un usuario al identificador de conexión y conservar esa asignación podrían realizar una de las siguientes acciones:

  • Conservar la asignación de una o varias conexiones como grupos. Consulte Grupos en SignalR para obtener más información.
  • Conservar la información de conexión y usuario a través de un servicio de base de datos única. Consulte Inserción de servicios en un concentrador para obtener más información. El servicio de base de datos única puede usar cualquier método de almacenamiento, como:
    • Almacenamiento en memoria en un diccionario.
    • Almacenamiento externo permanente. Por ejemplo, una base de datos o el almacenamiento de Azure Table mediante el paquete NuGet Azure.Data.Tables.
  • Pase el identificador de conexión entre los clientes.

Obtención de una instancia de IHubContext de IHost

El acceso a un IHubContext desde el host web resulta útil para la integración con áreas externas de ASP.NET Core, por ejemplo, mediante marcos de inserción de dependencias de terceros:

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

Inserción de un HubContext fuertemente tipado

Para insertar un HubContext fuertemente tipado, asegúrese de que el concentrador herede de Hub<T>. Inyecte mediante la interfaz IHubContext<THub, T> en lugar 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 Concentradores fuertemente tipados para obtener más información.

Use IHubContext en código genérico

Una instancia IHubContext<THub> insertada se puede convertir a IHubContext sin un tipo Hub genérico 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());
}

Resulta útil cuando:

  • Escribir bibliotecas que no tienen una referencia al tipo Hub específico que usa la aplicación.
  • Escritura de código genérico y que se puede aplicar a varias implementaciones Hub diferentes

Recursos adicionales