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 (procedura per il download)
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 ConnectionId
proprietà , Caller
e 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());
}
Questa operazione è 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