Inviare messaggi dall'esterno di un hub

L'hub SignalR è l'astrazione principale per l'invio di messaggi ai client connessi al SignalR server. È anche possibile inviare messaggi da altre posizioni dell'app usando il IHubContext servizio. Questo articolo illustra come accedere a per SignalRIHubContext inviare notifiche ai client dall'esterno di un hub.

Nota

è per l'invio IHubContext di notifiche ai client, non viene usato per chiamare i metodi in Hub.

Visualizzare o scaricare il codice di esempio (come scaricare)

Ottenere un'istanza di IHubContext

In ASP.NET Core SignalRè possibile accedere a un'istanza di IHubContext tramite inserimento delle dipendenze. È possibile inserire un'istanza di IHubContext in un controller, un middleware o un altro servizio di inserimento delle dipendenze. Usare l'istanza di per inviare messaggi ai client.

Inserire un'istanza di IHubContext in un controller

È possibile inserire un'istanza di IHubContext in un controller aggiungendola al costruttore:

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

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

Con l'accesso a un'istanza di IHubContext, chiamare i metodi client come se si trovasse nell'hub stesso:

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

Ottenere un'istanza di IHubContext nel middleware

Accedere all'oggetto IHubContext all'interno della pipeline middleware come illustrato di seguito:

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

Nota

Quando i metodi client vengono chiamati dall'esterno della Hub classe, non esiste alcun chiamante associato alla chiamata. Di conseguenza, non è possibile accedere alle ConnectionIdproprietà , Callere Others .

Le app che devono eseguire il mapping di un utente all'ID connessione e rendere persistente il mapping possono eseguire una delle operazioni seguenti:

  • Rendere persistente il mapping di connessioni singole o multiple come gruppi. Per altre informazioni, vedere Gruppi in SignalR .
  • Mantenere le informazioni di connessione e utente tramite un servizio singleton. Per altre informazioni, vedere Inserire servizi in un hub . Il servizio singleton può usare qualsiasi metodo di archiviazione, ad esempio:
    • Archiviazione in memoria in un dizionario.
    • Archiviazione esterna permanente. Ad esempio, un database o un archivio tabelle di Azure usando il pacchetto NuGet Azure.Data.Tables.
  • Passare l'ID connessione tra i client.

Ottenere un'istanza di IHubContext da IHost

L'accesso a un IHubContext dall'host Web è utile per l'integrazione con aree esterne a ASP.NET Core, ad esempio usando framework di inserimento delle dipendenze di terze parti:

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

Inserire un hubcontext fortemente tipizzato

Per inserire un HubContext fortemente tipizzato, assicurarsi che l'hub erediti da Hub<T>. Inserire l'interfaccia usando l'interfaccia IHubContext<THub, T> anziché 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);
    }
}

Per altre informazioni, vedere Hub fortemente tipizzato.

Usare IHubContext nel codice generico

È possibile eseguire il cast di un'istanza inserita IHubContext<THub> in IHubContext senza un tipo generico Hub specificato.

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

Ciò è utile quando:

  • Scrittura di librerie che non hanno un riferimento al tipo specifico Hub usato dall'app.
  • Scrittura di codice generico e applicabile a più implementazioni diverse Hub

Risorse aggiuntive