Senden von Nachrichten von außerhalb eines Hubs

Der SignalR-Hub ist die zentrale Abstraktion zum Senden von Nachrichten an Clients, die mit dem SignalR-Server verbunden sind. Es ist auch möglich, Nachrichten von anderen Stellen in Ihrer App zu senden, indem Sie den IHubContext-Dienst verwenden. In diesem Artikel wird erklärt, wie Sie auf SignalRIHubContext zugreifen, um Benachrichtigungen an Clients von außerhalb eines Hubs zu senden.

Hinweis

IHubContext dient zum Senden von Benachrichtigungen an Clients, aber wird nicht zum Aufrufen von Methoden in Hub verwendet.

Beispielcode anzeigen oder herunterladen (Vorgehensweise zum Herunterladen)

Abrufen einer Instanz von IHubContext

In ASP.NET Core SignalR können Sie über Dependency Injection (DI) auf eine Instanz von IHubContext zugreifen. Sie können eine Instanz von IHubContext in einen Controller, eine Middleware oder einen anderen DI-Dienst einfügen. Mithilfe dieser Instanz können Sie Nachrichten an Clients senden.

Einfügen einer Instanz von IHubContext in einen Controller

Sie können eine Instanz von IHubContext in einen Controller einfügen, indem Sie sie Ihrem Konstruktor hinzufügen:

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

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

Mit Zugriff auf eine Instanz von IHubContext rufen Sie Clientmethoden auf, als ob Sie sich auf dem Hub selbst befänden:

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

Abrufen einer Instanz von IHubContext in Middleware

Greifen Sie innerhalb der Middlewarepipeline wie folgt auf IHubContext zu:

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

Hinweis

Wenn Clientmethoden von außerhalb der Hub-Klasse aufgerufen werden, ist dem Aufruf kein Aufrufer zugeordnet. Daher ist kein Zugriff auf die Eigenschaften ConnectionId, Caller und Others möglich.

Apps, die einen Benutzer der Verbindungs-ID zuordnen und diese Zuordnung beibehalten müssen, haben folgende Möglichkeiten:

  • Beibehalten der Zuordnung einzelner oder mehrerer Verbindungen als Gruppen. Weitere Informationen finden Sie unter Gruppen in SignalR.
  • Beibehalten von Verbindungs- und Benutzerinformationen über einen Singletondienst. Weitere Informationen finden Sie unter Einfügen von Diensten in einen Hub. Der Singletondienst kann eine beliebige Speichermethode verwenden, z. B.:
    • In-Memory-Speicher in einem Wörterbuch.
    • Permanenten externer Speicher. Beispielsweise eine Datenbank oder Azure Table Storage unter Verwendung des NuGet-Pakets Azure.Data.Tables.
  • Übergeben der Verbindungs-ID zwischen Clients.

Abrufen einer Instanz von IHubContext von IHost

Der Zugriff auf IHubContext vom Webhost aus ist nützlich für die Integration mit Bereichen außerhalb von ASP.NET Core, z. B. unter Verwendung von Dependency Injection-Frameworks von Drittanbietern:

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

Einfügen einer stark typisierten HubContext-Instanz

Um eine stark typisierte HubContext-Instanz einzufügen, stellen Sie sicher, dass Ihr Hub von Hub<T> erbt. Fügen Sie sie mithilfe der IHubContext<THub, T>-Schnittstelle statt mit IHubContext<THub> ein.

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

Weitere Informationen finden Sie unter Stark typisierte Hubs.

Verwenden von IHubContext in generischem Code

Eine eingefügte IHubContext<THub>-Instanz kann ohne Angabe eines generischen Hub-Typs in IHubContext umgewandelt werden.

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

Diese Möglichkeit ist in folgenden Situationen nützlich:

  • Schreiben von Bibliotheken, die keinen Verweis auf den spezifischen Hub-Typ aufweisen, den die App verwendet.
  • Schreiben von Code, der generisch ist und auf mehrere verschiedene Hub-Implementierungen angewendet werden kann

Zusätzliche Ressourcen