Share via


ASP.NET SignalR Hubs-API-Leitfaden – Server (SignalR 1.x)

von Patrick Fletcher, Tom Dykstra

Warnung

Diese Dokumentation ist nicht für die neueste Version von SignalR vorgesehen. Sehen Sie sich ASP.NET Core SignalR an.

Dieses Dokument bietet eine Einführung in die Programmierung der Serverseite der ASP.NET SignalR Hubs-API für SignalR Version 1.1 mit Codebeispielen, die allgemeine Optionen veranschaulichen.

Mit der SignalR Hubs-API können Sie Remoteprozeduraufrufe (RPCs) von einem Server zu verbundenen Clients und von Clients zum Server ausführen. Im Servercode definieren Sie Methoden, die von Clients aufgerufen werden können, und rufen Methoden auf, die auf dem Client ausgeführt werden. Im Clientcode definieren Sie Methoden, die vom Server aufgerufen werden können, und rufen Methoden auf, die auf dem Server ausgeführt werden. SignalR übernimmt die gesamte Client-zu-Server-Sanitärinstallation für Sie.

SignalR bietet auch eine API auf niedrigerer Ebene namens Persistent Connections. Eine Einführung in SignalR, Hubs und persistente Verbindungen oder ein Tutorial zum Erstellen einer vollständigen SignalR-Anwendung finden Sie unter SignalR – Erste Schritte.

Überblick

Dieses Dokument enthält folgende Abschnitte:

Eine Dokumentation zum Programmieren von Clients finden Sie in den folgenden Ressourcen:

Links zu API-Referenzthemen beziehen sich auf die .NET 4.5-Version der API. Wenn Sie .NET 4 verwenden, lesen Sie die .NET 4-Version der API-Themen.

Registrieren der SignalR-Route und Konfigurieren von SignalR-Optionen

Um die Route zu definieren, die Clients zum Herstellen einer Verbindung mit Ihrem Hub verwenden, rufen Sie die MapHubs-Methode auf, wenn die Anwendung gestartet wird. MapHubs ist eine Erweiterungsmethode für die System.Web.Routing.RouteCollection -Klasse. Das folgende Beispiel zeigt, wie die SignalR Hubs-Route in der Datei Global.asax definiert wird.

using System.Web.Routing;
public class Global : System.Web.HttpApplication
{
    protected void Application_Start(object sender, EventArgs e)
    {
        RouteTable.Routes.MapHubs();
    }
}

Wenn Sie signalR-Funktionalität zu einer ASP.NET MVC-Anwendung hinzufügen, stellen Sie sicher, dass die SignalR-Route vor den anderen Routen hinzugefügt wird. Weitere Informationen finden Sie unter Tutorial: Erste Schritte mit SignalR und MVC 4.

Die /signalr-URL

Standardmäßig lautet die Routen-URL, die Clients zum Herstellen einer Verbindung mit Ihrem Hub verwenden, "/signalr". (Verwechseln Sie diese URL nicht mit der URL "/signalr/hubs", die für die automatisch generierte JavaScript-Datei gilt. Weitere Informationen zum generierten Proxy finden Sie unter SignalR Hubs API Guide – JavaScript Client – Der generierte Proxy und was er für Sie tut.)

Es kann außergewöhnliche Umstände geben, die dazu führen, dass diese Basis-URL für SignalR nicht verwendet werden kann. Beispielsweise haben Sie einen Ordner mit dem Namen signalr in Ihrem Projekt, und Sie möchten den Namen nicht ändern. In diesem Fall können Sie die Basis-URL ändern, wie in den folgenden Beispielen gezeigt (ersetzen Sie "/signalr" im Beispielcode durch die gewünschte URL).

Servercode, der die URL angibt

RouteTable.Routes.MapHubs("/signalr", new HubConfiguration());

JavaScript-Clientcode, der die URL angibt (mit dem generierten Proxy)

$.connection.hub.url = "/signalr"
$.connection.hub.start().done(init);

JavaScript-Clientcode, der die URL angibt (ohne den generierten Proxy)

var connection = $.hubConnection("/signalr", { useDefaultPath: false });

.NET-Clientcode, der die URL angibt

var hubConnection = new HubConnection("http://contoso.com/signalr", useDefaultUrl: false);

Konfigurieren von Signalr-Optionen

Mit Überladungen der MapHubs -Methode können Sie eine benutzerdefinierte URL, einen benutzerdefinierten Abhängigkeitslöser und die folgenden Optionen angeben:

  • Aktivieren Sie domänenübergreifende Aufrufe von Browserclients.

    Wenn der Browser eine Seite aus http://contoso.comlädt, befindet sich die SignalR-Verbindung in der gleichen Domäne unter http://contoso.com/signalr. Wenn die Seite von http://contoso.com eine Verbindung mit herstellt, handelt es sich um http://fabrikam.com/signalreine domänenübergreifende Verbindung. Aus Sicherheitsgründen sind domänenübergreifende Verbindungen standardmäßig deaktiviert. Weitere Informationen finden Sie unter ASP.NET SignalR Hubs-API-Leitfaden – JavaScript-Client – Herstellen einer domänenübergreifenden Verbindung.

  • Aktivieren Sie detaillierte Fehlermeldungen.

    Wenn Fehler auftreten, besteht das Standardverhalten von SignalR darin, eine Benachrichtigung ohne Details zu den Vorgängen an Clients zu senden. Das Senden ausführlicher Fehlerinformationen an Clients wird in der Produktion nicht empfohlen, da böswillige Benutzer die Informationen möglicherweise bei Angriffen auf Ihre Anwendung verwenden können. Zur Problembehandlung können Sie diese Option verwenden, um vorübergehend informativere Fehlerberichterstattung zu aktivieren.

  • Deaktivieren Sie automatisch generierte JavaScript-Proxydateien.

    Standardmäßig wird eine JavaScript-Datei mit Proxys für Ihre Hubklassen als Antwort auf die URL "/signalr/hubs" generiert. Wenn Sie die JavaScript-Proxys nicht verwenden möchten oder wenn Sie diese Datei manuell generieren und auf eine physische Datei in Ihren Clients verweisen möchten, können Sie diese Option verwenden, um die Proxygenerierung zu deaktivieren. Weitere Informationen finden Sie unter SignalR Hubs API Guide – JavaScript Client – How to create a physical file for the SignalR generated proxy.

Das folgende Beispiel zeigt, wie die SignalR-Verbindungs-URL und diese Optionen in einem Aufruf der MapHubs -Methode angegeben werden. Um eine benutzerdefinierte URL anzugeben, ersetzen Sie "/signalr" im Beispiel durch die URL, die Sie verwenden möchten.

var hubConfiguration = new HubConfiguration();
hubConfiguration.EnableCrossDomain = true;
hubConfiguration.EnableDetailedErrors = true;
hubConfiguration.EnableJavaScriptProxies = false;
RouteTable.Routes.MapHubs("/signalr", hubConfiguration);

Erstellen und Verwenden von Hubklassen

Um einen Hub zu erstellen, erstellen Sie eine Klasse, die von Microsoft.Aspnet.Signalr.Hub abgeleitet ist. Das folgende Beispiel zeigt eine einfache Hub-Klasse für eine Chatanwendung.

public class ContosoChatHub : Hub
{
    public void NewContosoChatMessage(string name, string message)
    {
        Clients.All.addNewMessageToPage(name, message);
    }
}

In diesem Beispiel kann ein verbundener Client die NewContosoChatMessage -Methode aufrufen, und wenn dies der Fall ist, werden die empfangenen Daten an alle verbundenen Clients übertragen.

Hubobjektlebensdauer

Sie instanziieren die Hub-Klasse nicht oder rufen ihre Methoden nicht aus Ihrem eigenen Code auf dem Server auf. All dies wird von der SignalR Hubs-Pipeline für Sie erledigt. SignalR erstellt jedes Mal eine neue instance Ihrer Hub-Klasse, wenn ein Hubvorgang verarbeitet werden muss, z. B. wenn ein Client eine Verbindung mit dem Server herstellt, trennt oder einen Methodenaufruf an den Server sendet.

Da Instanzen der Hub-Klasse vorübergehend sind, können Sie sie nicht verwenden, um den Zustand von einem Methodenaufruf zum nächsten beizubehalten. Jedes Mal, wenn der Server einen Methodenaufruf von einem Client empfängt, verarbeitet eine neue instance Ihrer Hub-Klasse die Nachricht. Um den Zustand über mehrere Verbindungen und Methodenaufrufe beizubehalten, verwenden Sie eine andere Methode, z. B. eine Datenbank, eine statische Variable in der Hub-Klasse oder eine andere Klasse, die nicht von Hubabgeleitet wird. Wenn Sie Daten im Arbeitsspeicher beibehalten und eine Methode wie eine statische Variable für die Hub-Klasse verwenden, gehen die Daten verloren, wenn die App-Domäne wiederverwendet wird.

Wenn Sie Nachrichten aus Ihrem eigenen Code an Clients senden möchten, der außerhalb der Hub-Klasse ausgeführt wird, können Sie dies nicht tun, indem Sie eine Hub-Klasse instance instanziieren, aber Sie können dies tun, indem Sie einen Verweis auf das SignalR-Kontextobjekt für Ihre Hub-Klasse abrufen. Weitere Informationen finden Sie weiter unten in diesem Thema unter Aufrufen von Clientmethoden und Verwalten von Gruppen von außerhalb der Hub-Klasse .

Camel-Casing von Hubnamen in JavaScript-Clients

JavaScript-Clients verweisen standardmäßig auf Hubs, indem sie eine Camel-Case-Version des Klassennamens verwenden. SignalR nimmt diese Änderung automatisch vor, damit JavaScript-Code den JavaScript-Konventionen entsprechen kann. Das vorherige Beispiel wird im JavaScript-Code als contosoChatHub bezeichnet.

Server

public class ContosoChatHub : Hub

JavaScript-Client mit generierten Proxys

var contosoChatHubProxy = $.connection.contosoChatHub;

Wenn Sie einen anderen Namen für clients angeben möchten, fügen Sie das HubName -Attribut hinzu. Wenn Sie ein HubName Attribut verwenden, erfolgt auf JavaScript-Clients keine Namensänderung in Camel Case.

Server

[HubName("PascalCaseContosoChatHub")]
public class ContosoChatHub : Hub

JavaScript-Client mit generierten Proxys

var contosoChatHubProxy = $.connection.PascalCaseContosoChatHub;

Mehrere Hubs

Sie können mehrere Hubklassen in einer Anwendung definieren. Wenn Sie dies tun, wird die Verbindung freigegeben, aber Gruppen sind getrennt:

  • Alle Clients verwenden dieselbe URL, um eine SignalR-Verbindung mit Ihrem Dienst ("/signalr" oder Ihrer benutzerdefinierten URL herzustellen, wenn Sie eine angegeben haben), und diese Verbindung wird für alle vom Dienst definierten Hubs verwendet.

    Es gibt keinen Leistungsunterschied für mehrere Hubs im Vergleich zur Definition aller Hubfunktionen in einer einzelnen Klasse.

  • Alle Hubs erhalten dieselben HTTP-Anforderungsinformationen.

    Da alle Hubs dieselbe Verbindung verwenden, erhält der Server nur http-Anforderungsinformationen, die in der ursprünglichen HTTP-Anforderung enthalten sind, die die SignalR-Verbindung herstellt. Wenn Sie die Verbindungsanforderung verwenden, um Informationen vom Client an den Server zu übergeben, indem Sie eine Abfragezeichenfolge angeben, können Sie keine anderen Abfragezeichenfolgen für verschiedene Hubs bereitstellen. Alle Hubs erhalten dieselben Informationen.

  • Die generierte JavaScript-Proxydatei enthält Proxys für alle Hubs in einer Datei.

    Informationen zu JavaScript-Proxys finden Sie unter SignalR Hubs API Guide – JavaScript Client – Der generierte Proxy und was er für Sie tut.

  • Gruppen werden innerhalb von Hubs definiert.

    In SignalR können Sie benannte Gruppen definieren, die an Teilmengen verbundener Clients übertragen werden sollen. Gruppen werden für jeden Hub separat verwaltet. Beispielsweise würde eine Gruppe mit dem Namen "Administratoren" einen Satz von Clients für Ihre ContosoChatHub Klasse enthalten, und derselbe Gruppenname bezieht sich auf einen anderen Satz von Clients für Ihre StockTickerHub Klasse.

Definieren von Methoden in der Hub-Klasse, die Clients aufrufen können

Um eine Methode auf dem Hub verfügbar zu machen, die vom Client aufgerufen werden soll, deklarieren Sie eine öffentliche Methode, wie in den folgenden Beispielen gezeigt.

public class ContosoChatHub : Hub
{
    public void NewContosoChatMessage(string name, string message)
    {
        Clients.All.addNewMessageToPage(name, message);
    }
}
public class StockTickerHub : Hub
{
    public IEnumerable<Stock> GetAllStocks()
    {
        return _stockTicker.GetAllStocks();
    }
}

Sie können wie in jeder C#-Methode einen Rückgabetyp und Parameter angeben, einschließlich komplexer Typen und Arrays. Alle Daten, die Sie in Parametern empfangen oder an den Aufrufer zurückgeben, werden zwischen dem Client und dem Server mithilfe von JSON kommuniziert, und SignalR verarbeitet die Bindung komplexer Objekte und Objektarrays automatisch.

Camel-Casing von Methodennamen in JavaScript-Clients

JavaScript-Clients verweisen standardmäßig auf Hub-Methoden, indem sie eine Camel-Case-Version des Methodennamens verwenden. SignalR nimmt diese Änderung automatisch vor, damit JavaScript-Code den JavaScript-Konventionen entsprechen kann.

Server

public void NewContosoChatMessage(string userName, string message)

JavaScript-Client mit generierten Proxys

contosoChatHubProxy.server.newContosoChatMessage($(userName, message);

Wenn Sie einen anderen Namen für clients angeben möchten, fügen Sie das HubMethodName -Attribut hinzu.

Server

[HubMethodName("PascalCaseNewContosoChatMessage")]
public void NewContosoChatMessage(string userName, string message)

JavaScript-Client mit generierten Proxys

contosoChatHubProxy.server.PascalCaseNewContosoChatMessage(userName, message);

Zeitpunkt der asynchronen Ausführung

Wenn die Methode lange ausgeführt wird oder Aufgaben ausführen muss, die warten, z. B. eine Datenbanksuche oder einen Webdienstaufruf, führen Sie die Hub-Methode asynchron aus, indem Sie ein Task-Objekt (anstelle der Rückgabe) oder ein Task T-Objekt<> (anstelle des void RückgabetypsT) zurückgeben. Wenn Sie ein Task Objekt von der -Methode zurückgeben, wartet SignalR auf den Abschluss von Task und sendet dann das entpackte Ergebnis zurück an den Client, sodass es keinen Unterschied in der Art und Weise gibt, wie Sie den Methodenaufruf im Client codieren.

Wenn Sie eine Hub-Methode asynchron erstellen, wird vermieden, dass die Verbindung blockiert wird, wenn sie den WebSocket-Transport verwendet. Wenn eine Hub-Methode synchron ausgeführt wird und der Transport WebSocket ist, werden nachfolgende Aufrufe von Methoden auf dem Hub vom gleichen Client blockiert, bis die Hub-Methode abgeschlossen ist.

Das folgende Beispiel zeigt die gleiche Methode, die für die synchrone oder asynchrone Ausführung codiert ist, gefolgt von JavaScript-Clientcode, der zum Aufrufen beider Versionen funktioniert.

Synchron

public IEnumerable<Stock> GetAllStocks()
{
    // Returns data from memory.
    return _stockTicker.GetAllStocks();
}

Asynchron– ASP.NET 4.5

public async Task<IEnumerable<Stock>> GetAllStocks()
{
    // Returns data from a web service.
    var uri = Util.getServiceUri("Stocks");
    using (HttpClient httpClient = new HttpClient())
    {
        var response = await httpClient.GetAsync(uri);
        return (await response.Content.ReadAsAsync<IEnumerable<Stock>>());
    }
}

JavaScript-Client mit generierten Proxys

stockTickerHubProxy.server.getAllStocks().done(function (stocks) {
    $.each(stocks, function () {
        alert(this.Symbol + ' ' + this.Price);
    });
});

Weitere Informationen zur Verwendung asynchroner Methoden in ASP.NET 4.5 finden Sie unter Verwenden asynchroner Methoden in ASP.NET MVC 4.

Definieren von Überladungen

Wenn Sie Überladungen für eine Methode definieren möchten, muss die Anzahl der Parameter in jeder Überladung unterschiedlich sein. Wenn Sie eine Überladung nur durch Angabe verschiedener Parametertypen unterscheiden, wird Ihre Hub-Klasse kompiliert, aber der SignalR-Dienst löst zur Laufzeit eine Ausnahme aus, wenn Clients versuchen, eine der Überladungen aufzurufen.

Aufrufen von Clientmethoden aus der Hub-Klasse

Um Clientmethoden vom Server aufzurufen, verwenden Sie die Clients -Eigenschaft in einer -Methode in Ihrer Hub-Klasse. Das folgende Beispiel zeigt Servercode, der auf allen verbundenen Clients aufruft addNewMessageToPage , und Clientcode, der die -Methode in einem JavaScript-Client definiert.

Server

public class ContosoChatHub : Hub
{
    public void NewContosoChatMessage(string name, string message)
    {
        Clients.All.addNewMessageToPage(name, message);
    }
}

JavaScript-Client mit generierten Proxys

contosoChatHubProxy.client.addNewMessageToPage = function (name, message) {
    // Add the message to the page. 
    $('#discussion').append('<li><strong>' + htmlEncode(name)
        + '</strong>: ' + htmlEncode(message) + '<li>');
};

Sie können keinen Rückgabewert von einer Clientmethode abrufen. Syntax wie int x = Clients.All.add(1,1) funktioniert nicht.

Sie können komplexe Typen und Arrays für die Parameter angeben. Im folgenden Beispiel wird ein komplexer Typ in einem Methodenparameter an den Client übergeben.

Servercode, der eine Clientmethode mithilfe eines komplexen Objekts aufruft

public void SendMessage(string name, string message)
{
    Clients.All.addContosoChatMessageToPage(new ContosoChatMessage() { UserName = name, Message = message });
}

Servercode, der das komplexe Objekt definiert

public class ContosoChatMessage
{
    public string UserName { get; set; }
    public string Message { get; set; }
}

JavaScript-Client mit generierten Proxys

var contosoChatHubProxy = $.connection.contosoChatHub;
contosoChatHubProxy.client.addMessageToPage = function (message) {
    console.log(message.UserName + ' ' + message.Message);
});

Auswählen der Clients, die den RPC erhalten sollen

Die Clients-Eigenschaft gibt ein HubConnectionContext-Objekt zurück, das mehrere Optionen für die Angabe bietet, welche Clients den RPC empfangen:

  • Alle verbundenen Clients.

    Clients.All.addContosoChatMessageToPage(name, message);
    
  • Nur der aufrufende Client.

    Clients.Caller.addContosoChatMessageToPage(name, message);
    
  • Alle Clients mit Ausnahme des aufrufenden Clients.

    Clients.Others.addContosoChatMessageToPage(name, message);
    
  • Ein bestimmter Client, der durch die Verbindungs-ID identifiziert wird.

    Clients.Client(Context.ConnectionId).addContosoChatMessageToPage(name, message);
    

    In diesem Beispiel wird der aufrufende Client aufgerufen addContosoChatMessageToPage und hat die gleiche Auswirkung wie die Verwendung von Clients.Caller.

  • Alle verbundenen Clients mit Ausnahme der angegebenen Clients, die durch die Verbindungs-ID identifiziert werden.

    Clients.AllExcept(connectionId1, connectionId2).addContosoChatMessageToPage(name, message);
    
  • Alle verbundenen Clients in einer angegebenen Gruppe.

    Clients.Group(groupName).addContosoChatMessageToPage(name, message);
    
  • Alle verbundenen Clients in einer angegebenen Gruppe mit Ausnahme der angegebenen Clients, die durch die Verbindungs-ID identifiziert werden.

    Clients.Group(groupName, connectionId1, connectionId2).addContosoChatMessageToPage(name, message);
    
  • Alle verbundenen Clients in einer angegebenen Gruppe mit Ausnahme des aufrufenden Clients.

    Clients.OthersInGroup(groupName).addContosoChatMessageToPage(name, message);
    

Keine Validierung zur Kompilierzeit für Methodennamen

Der von Ihnen angegebene Methodenname wird als dynamisches Objekt interpretiert, was bedeutet, dass es keine IntelliSense- oder Kompilierzeitüberprüfung dafür gibt. Der Ausdruck wird zur Laufzeit ausgewertet. Wenn der Methodenaufruf ausgeführt wird, sendet SignalR den Methodennamen und die Parameterwerte an den Client, und wenn der Client über eine Methode verfügt, die dem Namen entspricht, wird diese Methode aufgerufen, und die Parameterwerte werden an sie übergeben. Wenn auf dem Client keine übereinstimmende Methode gefunden wird, wird kein Fehler ausgelöst. Informationen zum Format der Daten, die SignalR im Hintergrund beim Aufrufen einer Clientmethode an den Client übermittelt, finden Sie unter Einführung in SignalR.

Abgleich von Methodennamen ohne Berücksichtigung der Groß-/Kleinschreibung

Beim Methodennamenabgleich wird die Groß-/Kleinschreibung nicht beachtet. Auf dem Server wird beispielsweise Clients.All.addContosoChatMessageToPage , addcontosochatmessagetopageoder addContosoChatMessageToPage auf dem Client ausgeführtAddContosoChatMessageToPage.

Asynchrone Ausführung

Die Methode, die Sie aufrufen, wird asynchron ausgeführt. Jeder Code, der nach einem Methodenaufruf an einen Client eingeht, wird sofort ausgeführt, ohne darauf zu warten, dass SignalR die Übertragung von Daten an Clients beendet, es sei denn, Sie geben an, dass die nachfolgenden Codezeilen auf den Abschluss der Methode warten sollen. In den folgenden Codebeispielen wird gezeigt, wie zwei Clientmethoden sequenziell ausgeführt werden, eine mit Code, der in .NET 4.5 funktioniert, und eine mit Code, der in .NET 4 funktioniert.

.NET 4.5-Beispiel

async public Task NewContosoChatMessage(string name, string message)
{
    await Clients.Others.addContosoChatMessageToPage(data);
    Clients.Caller.notifyMessageSent();
}

.NET 4-Beispiel

public void NewContosoChatMessage(string name, string message)
{
    (Clients.Others.addContosoChatMessageToPage(data) as Task).ContinueWith(antecedent =>
        Clients.Caller.notifyMessageSent());
}

Wenn Sie oder verwenden await , ContinueWith um zu warten, bis eine Clientmethode abgeschlossen ist, bevor die nächste Codezeile ausgeführt wird, bedeutet dies nicht, dass Clients die Nachricht tatsächlich empfangen, bevor die nächste Codezeile ausgeführt wird. "Abschluss" eines Clientmethodenaufrufs bedeutet nur, dass SignalR alles getan hat, was zum Senden der Nachricht erforderlich ist. Wenn Sie überprüfen müssen, ob Clients die Nachricht erhalten haben, müssen Sie diesen Mechanismus selbst programmieren. Beispielsweise könnten Sie eine MessageReceived Methode auf dem Hub codieren, und in der addContosoChatMessageToPage -Methode auf dem Client können Sie aufrufen MessageReceived , nachdem Sie die erforderlichen Aufgaben auf dem Client ausgeführt haben. Im MessageReceived Hub können Sie jede Arbeit erledigen, die vom tatsächlichen Clientempfang und der Verarbeitung des ursprünglichen Methodenaufrufs abhängt.

Verwenden einer Zeichenfolgenvariablen als Methodenname

Wenn Sie eine Clientmethode aufrufen möchten, indem Sie eine Zeichenfolgenvariable als Methodennamen verwenden, wandeln Sie Clients.All (oder Clients.Others, Clients.Callerusw.) in IClientProxy um, und rufen Sie dann Invoke(methodName, args...)auf.

public void NewContosoChatMessage(string name, string message)
{
    string methodToCall = "addContosoChatMessageToPage";
    IClientProxy proxy = Clients.All;
    proxy.Invoke(methodToCall, name, message);
}

Verwalten der Gruppenmitgliedschaft über die Hub-Klasse

Gruppen in SignalR stellen eine Methode zum Senden von Nachrichten an bestimmte Teilmengen verbundener Clients bereit. Eine Gruppe kann über eine beliebige Anzahl von Clients verfügen, und ein Client kann Mitglied einer beliebigen Anzahl von Gruppen sein.

Verwenden Sie zum Verwalten der Gruppenmitgliedschaft die Methoden Add und Remove , die von der Groups -Eigenschaft der Hub-Klasse bereitgestellt werden. Das folgende Beispiel zeigt die Groups.Add Methoden und Groups.Remove in Hub-Methoden, die vom Clientcode aufgerufen werden, gefolgt von JavaScript-Clientcode, der sie aufruft.

Server

public class ContosoChatHub : Hub
{
    public Task JoinGroup(string groupName)
    {
        return Groups.Add(Context.ConnectionId, groupName);
    }

    public Task LeaveGroup(string groupName)
    {
        return Groups.Remove(Context.ConnectionId, groupName);
    }
}

JavaScript-Client mit generierten Proxys

contosoChatHubProxy.server.joinGroup(groupName);
contosoChatHubProxy.server.leaveGroup(groupName);

Sie müssen keine Gruppen explizit erstellen. In der Tat wird eine Gruppe automatisch erstellt, wenn Sie ihren Namen zum ersten Mal in einem Aufruf Groups.Addvon angeben, und sie wird gelöscht, wenn Sie die letzte Verbindung aus der Mitgliedschaft entfernen.

Es gibt keine API zum Abrufen einer Gruppenmitgliedschaftsliste oder einer Liste von Gruppen. SignalR sendet Nachrichten an Clients und Gruppen basierend auf einem Pub-/Untermodell, und der Server verwaltet keine Listen mit Gruppen oder Gruppenmitgliedschaften. Dies trägt zur Maximierung der Skalierbarkeit bei, denn wenn Sie einer Webfarm einen Knoten hinzufügen, muss jeder Zustand, den SignalR verwaltet, an den neuen Knoten weitergegeben werden.

Asynchrone Ausführung der Methoden "Hinzufügen" und "Entfernen"

Die Groups.Add Methoden und Groups.Remove werden asynchron ausgeführt. Wenn Sie einer Gruppe einen Client hinzufügen und mithilfe der Gruppe sofort eine Nachricht an den Client senden möchten, müssen Sie sicherstellen, dass die Groups.Add Methode zuerst abgeschlossen wird. Die folgenden Codebeispiele zeigen, wie dies geht, eines mithilfe von Code, der in .NET 4.5 funktioniert, und eines mithilfe von Code, der in .NET 4 funktioniert

.NET 4.5-Beispiel

async public Task JoinGroup(string groupName)
{
    await Groups.Add(Context.ConnectionId, groupName);
    Clients.Group(groupname).addContosoChatMessageToPage(Context.ConnectionId + " added to group");
}

.NET 4-Beispiel

public void JoinGroup(string groupName)
{
    (Groups.Add(Context.ConnectionId, groupName) as Task).ContinueWith(antecedent =>
        Clients.Group(groupName).addContosoChatMessageToPage(Context.ConnectionId + " added to group"));
}

Persistenz der Gruppenmitgliedschaft

SignalR verfolgt Verbindungen nach, nicht Benutzer. Wenn ein Benutzer also jedes Mal, wenn der Benutzer eine Verbindung herstellt, in derselben Gruppe sein soll, müssen Sie jedes Mal aufrufen Groups.Add , wenn der Benutzer eine neue Verbindung herstellt.

Nach einem vorübergehenden Verbindungsverlust kann SignalR die Verbindung manchmal automatisch wiederherstellen. In diesem Fall stellt SignalR dieselbe Verbindung wieder her, stellt keine neue Verbindung her, sodass die Gruppenmitgliedschaft des Clients automatisch wiederhergestellt wird. Dies ist auch möglich, wenn die temporäre Unterbrechung das Ergebnis eines Serverneustarts oder -fehlers ist, da der Verbindungszustand für jeden Client, einschließlich Gruppenmitgliedschaften, auf den Client umgedreht wird. Wenn ein Server ausfällt und durch einen neuen Server ersetzt wird, bevor das Verbindungstimeout ausfällt, kann ein Client automatisch wieder eine Verbindung mit dem neuen Server herstellen und sich erneut in Gruppen registrieren, in denen er Mitglied ist.

Wenn eine Verbindung nach einem Verbindungsverlust nicht automatisch wiederhergestellt werden kann, wenn die Verbindung ein Timeout aufweist oder wenn der Client getrennt wird (z. B. wenn ein Browser zu einer neuen Seite navigiert), gehen Gruppenmitgliedschaften verloren. Das nächste Mal, wenn der Benutzer eine Verbindung herstellt, wird eine neue Verbindung hergestellt. Um Gruppenmitgliedschaften beizubehalten, wenn derselbe Benutzer eine neue Verbindung herstellt, muss Ihre Anwendung die Zuordnungen zwischen Benutzern und Gruppen nachverfolgen und die Gruppenmitgliedschaften jedes Mal wiederherstellen, wenn ein Benutzer eine neue Verbindung herstellt.

Weitere Informationen zu Verbindungen und erneuten Verbindungen finden Sie weiter unten in diesem Thema unter Behandeln von Verbindungslebensdauerereignissen in der Hub-Klasse .

Einzelbenutzergruppen

Anwendungen, die SignalR verwenden, müssen in der Regel die Zuordnungen zwischen Benutzern und Verbindungen nachverfolgen, um zu wissen, welcher Benutzer eine Nachricht gesendet hat und welche Benutzer eine Nachricht erhalten sollen. Gruppen werden in einem der beiden häufig verwendeten Muster verwendet.

  • Einzelbenutzergruppen.

    Sie können den Benutzernamen als Gruppennamen angeben und der Gruppe jedes Mal die aktuelle Verbindungs-ID hinzufügen, wenn der Benutzer eine Verbindung herstellt oder die Verbindung wieder herstellt. Um Nachrichten an den Benutzer zu senden, den Sie an die Gruppe senden. Ein Nachteil dieser Methode ist, dass die Gruppe Ihnen keine Möglichkeit bietet, herauszufinden, ob der Benutzer online oder offline ist.

  • Nachverfolgen von Zuordnungen zwischen Benutzernamen und Verbindungs-IDs.

    Sie können eine Zuordnung zwischen jedem Benutzernamen und einer oder mehreren Verbindungs-IDs in einem Wörterbuch oder einer Datenbank speichern und die gespeicherten Daten jedes Mal aktualisieren, wenn der Benutzer eine Verbindung herstellt oder die Verbindung trennt. Um Nachrichten an den Benutzer zu senden, geben Sie die Verbindungs-IDs an. Ein Nachteil dieser Methode ist, dass sie mehr Arbeitsspeicher benötigt.

Behandeln von Verbindungslebensdauerereignissen in der Hub-Klasse

Typische Gründe für die Verarbeitung von Verbindungslebensdauerereignissen sind das Nachverfolgen, ob ein Benutzer verbunden ist oder nicht, und die Zuordnung zwischen Benutzernamen und Verbindungs-IDs nachzuverfolgen. Um Ihren eigenen Code auszuführen, wenn Clients eine Verbindung herstellen oder trennen, überschreiben Sie die OnConnectedvirtuellen Methoden , OnDisconnectedund OnReconnected der Hub-Klasse, wie im folgenden Beispiel gezeigt.

public class ContosoChatHub : Hub
{
    public override Task OnConnected()
    {
        // Add your own code here.
        // For example: in a chat application, record the association between
        // the current connection ID and user name, and mark the user as online.
        // After the code in this method completes, the client is informed that
        // the connection is established; for example, in a JavaScript client,
        // the start().done callback is executed.
        return base.OnConnected();
    }

    public override Task OnDisconnected()
    {
        // Add your own code here.
        // For example: in a chat application, mark the user as offline, 
        // delete the association between the current connection id and user name.
        return base.OnDisconnected();
    }

    public override Task OnReconnected()
    {
        // Add your own code here.
        // For example: in a chat application, you might have marked the
        // user as offline after a period of inactivity; in that case 
        // mark the user as online again.
        return base.OnReconnected();
    }
}

Wenn OnConnected, OnDisconnected und OnReconnected aufgerufen werden

Jedes Mal, wenn ein Browser zu einer neuen Seite navigiert, muss eine neue Verbindung hergestellt werden, was bedeutet, dass SignalR die OnDisconnected Methode gefolgt von der OnConnected -Methode ausführt. SignalR erstellt immer eine neue Verbindungs-ID, wenn eine neue Verbindung hergestellt wird.

Die OnReconnected -Methode wird aufgerufen, wenn eine vorübergehende Unterbrechung der Konnektivität aufgetreten ist, von der SignalR automatisch wiederhergestellt werden kann, z. B. wenn ein Kabel vorübergehend getrennt und wieder verbunden wird, bevor das Zeitüberschreitungs für die Verbindung ausbricht. Die OnDisconnected -Methode wird aufgerufen, wenn der Client getrennt wird und SignalR die Verbindung nicht automatisch wieder herstellen kann, z. B. wenn ein Browser zu einer neuen Seite navigiert. Daher ist OnConnectedeine mögliche Abfolge von Ereignissen für einen bestimmten Client , OnReconnected, OnDisconnectedoder OnConnected, OnDisconnected. Die Sequenz OnConnected, , OnDisconnectedwird OnReconnected für eine bestimmte Verbindung nicht angezeigt.

Die OnDisconnected Methode wird in einigen Szenarien nicht aufgerufen, z. B. wenn ein Server ausfällt oder die App-Domäne wiederverwendet wird. Wenn ein anderer Server online ist oder die App-Domäne den Wiederverwendungsvorgang abgeschlossen hat, können einige Clients möglicherweise eine Verbindung herstellen und das OnReconnected Ereignis auslösen.

Weitere Informationen finden Sie unter Grundlegendes und Behandeln von Verbindungslebensdauerereignissen in SignalR.

Aufruferstatus nicht aufgefüllt

Die Verbindungslebensdauer-Ereignishandlermethoden werden vom Server aufgerufen. Dies bedeutet, dass jeder Zustand, den Sie im -Objekt auf dem state Client einfügen, nicht in der Caller Eigenschaft auf dem Server aufgefüllt wird. Informationen zum state -Objekt und der Caller -Eigenschaft finden Sie weiter unten in diesem Thema unter Übergeben des Zustands zwischen Clients und der Hub-Klasse .

Abrufen von Informationen über den Client aus der Context-Eigenschaft

Um Informationen zum Client abzurufen, verwenden Sie die Context Eigenschaft der Hub-Klasse. Die Context -Eigenschaft gibt ein HubCallerContext-Objekt zurück, das Zugriff auf die folgenden Informationen bietet:

  • Die Verbindungs-ID des aufrufenden Clients.

    string connectionID = Context.ConnectionId;
    

    Die Verbindungs-ID ist eine GUID, die von SignalR zugewiesen wird (Sie können den Wert nicht in Ihrem eigenen Code angeben). Es gibt eine Verbindungs-ID für jede Verbindung, und die gleiche Verbindungs-ID wird von allen Hubs verwendet, wenn Sie mehrere Hubs in Ihrer Anwendung haben.

  • HTTP-Headerdaten.

    System.Collections.Specialized.NameValueCollection headers = Context.Request.Headers;
    

    Sie können auch HTTP-Header von Context.Headersabrufen. Der Grund für mehrere Verweise auf dasselbe Objekt ist, dass Context.Headers zuerst erstellt wurde, die Context.Request Eigenschaft wurde später hinzugefügt und Context.Headers aus Gründen der Abwärtskompatibilität beibehalten.

  • Abfragezeichenfolgendaten.

    System.Collections.Specialized.NameValueCollection queryString = Context.Request.QueryString;
    string parameterValue = queryString["parametername"]
    

    Sie können auch Abfragezeichenfolgendaten von Context.QueryStringabrufen.

    Die Abfragezeichenfolge, die Sie in dieser Eigenschaft abrufen, ist diejenige, die mit der HTTP-Anforderung verwendet wurde, die die SignalR-Verbindung hergestellt hat. Sie können Abfragezeichenfolgenparameter im Client hinzufügen, indem Sie die Verbindung konfigurieren. Dies ist eine bequeme Möglichkeit, Daten über den Client vom Client an den Server zu übergeben. Das folgende Beispiel zeigt eine Möglichkeit zum Hinzufügen einer Abfragezeichenfolge in einem JavaScript-Client, wenn Sie den generierten Proxy verwenden.

    $.connection.hub.qs = { "version" : "1.0" };
    

    Weitere Informationen zum Festlegen von Abfragezeichenfolgenparametern finden Sie in den API-Leitfäden für die JavaScript - und .NET-Clients .

    Sie finden die für die Verbindung verwendete Transportmethode in den Abfragezeichenfolgendaten sowie einige andere werte, die intern von SignalR verwendet werden:

    string transportMethod = queryString["transport"];
    

    Der Wert von transportMethod lautet "webSockets", "serverSentEvents", "foreverFrame" oder "longPolling". Wenn Sie diesen Wert in der OnConnected Ereignishandlermethode überprüfen, erhalten Sie in einigen Szenarien möglicherweise zunächst einen Transportwert, der nicht die endgültige ausgehandelte Transportmethode für die Verbindung ist. In diesem Fall löst die Methode eine Ausnahme aus und wird später erneut aufgerufen, wenn die endgültige Transportmethode eingerichtet wird.

  • Cookies.

    System.Collections.Generic.IDictionary<string, Cookie> cookies = Context.Request.Cookies;
    

    Sie können cookies auch von Context.RequestCookiesabrufen.

  • Benutzerinformationen.

    System.Security.Principal.IPrincipal user = Context.User;
    
  • Das HttpContext-Objekt für die Anforderung:

    System.Web.HttpContextBase httpContext = Context.Request.GetHttpContext();
    

    Verwenden Sie diese Methode, HttpContext.Current anstatt das -Objekt für die HttpContext SignalR-Verbindung abzurufen.

Übergeben des Zustands zwischen Clients und der Hub-Klasse

Der Clientproxy stellt ein state Objekt bereit, in dem Sie Daten speichern können, die Sie mit jedem Methodenaufruf an den Server übertragen möchten. Auf dem Server können Sie in der Eigenschaft in Hubmethoden, die Clients.Caller von Clients aufgerufen werden, auf diese Daten zugreifen. Die Clients.Caller -Eigenschaft wird nicht für die Verbindungslebensdauer-Ereignishandlermethoden OnConnected, OnDisconnectedund OnReconnectedaufgefüllt.

Das Erstellen oder Aktualisieren von Daten im state -Objekt und der Clients.Caller -Eigenschaft funktioniert in beide Richtungen. Sie können Werte auf dem Server aktualisieren, die an den Client zurückgegeben werden.

Das folgende Beispiel zeigt JavaScript-Clientcode, der den Zustand für die Übertragung an den Server mit jedem Methodenaufruf speichert.

contosoChatHubProxy.state.userName = "Fadi Fakhouri";
contosoChatHubProxy.state.computerName = "fadivm1";

Das folgende Beispiel zeigt den entsprechenden Code in einem .NET-Client.

contosoChatHubProxy["userName"] = "Fadi Fakhouri";
chatHubProxy["computerName"] = "fadivm1";

In Ihrer Hub-Klasse können Sie in der Clients.Caller -Eigenschaft auf diese Daten zugreifen. Das folgende Beispiel zeigt Code, der den Zustand abruft, auf den im vorherigen Beispiel verwiesen wurde.

public void NewContosoChatMessage(string data)
{
    string userName = Clients.Caller.userName;
    string computerName = Clients.Caller.computerName;
    Clients.Others.addContosoChatMessageToPage(message, userName, computerName);
}

Hinweis

Dieser Mechanismus zum Beibehalten des Zustands ist nicht für große Datenmengen vorgesehen, da alles, was Sie in die state -Eigenschaft oder Clients.Caller -Eigenschaft einfügen, bei jedem Methodenaufruf rundgedreht wird. Es ist nützlich für kleinere Elemente wie Benutzernamen oder Indikatoren.

Behandeln von Fehlern in der Hub-Klasse

Verwenden Sie eine oder beide der folgenden Methoden, um Fehler zu behandeln, die in Den Hub-Klassenmethoden auftreten:

  • Umschließen Sie Ihren Methodencode in try-catch-Blöcke, und protokollieren Sie das Ausnahmeobjekt. Zum Debuggen können Sie die Ausnahme an den Client senden, aber aus Sicherheitsgründen wird das Senden detaillierter Informationen an Clients in der Produktion nicht empfohlen.

  • Erstellen Sie ein Hubs-Pipelinemodul, das die OnIncomingError-Methode verarbeitet. Das folgende Beispiel zeigt ein Pipelinemodul, das Fehler protokolliert, gefolgt von Code in Global.asax, der das Modul in die Hubs-Pipeline einschleust.

    public class ErrorHandlingPipelineModule : HubPipelineModule
    {
        protected override void OnIncomingError(Exception ex, IHubIncomingInvokerContext context)
        {
            Debug.WriteLine("=> Exception " + ex.Message);
            if (ex.InnerException != null)
            {
                Debug.WriteLine("=> Inner Exception " + ex.InnerException.Message);
            }
            base.OnIncomingError(ex, context);
        }
    }
    
    protected void Application_Start(object sender, EventArgs e)
    {
        GlobalHost.HubPipeline.AddModule(new ErrorHandlingPipelineModule()); 
        RouteTable.Routes.MapHubs();
    }
    

Weitere Informationen zu Hubpipelinemodulen finden Sie weiter unten in diesem Thema unter Anpassen der Hubs-Pipeline .

Aktivieren der Ablaufverfolgung

Um die serverseitige Ablaufverfolgung zu aktivieren, fügen Sie ein System hinzu. Diagnose -Element in Ihre Web.config-Datei ein, wie in diesem Beispiel gezeigt:

<configuration>
  <configSections>
    <!-- For more information on Entity Framework configuration, visit https://go.microsoft.com/fwlink/?LinkID=237468 -->
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
  </configSections>
  <connectionStrings>
    <add name="SignalRSamples" connectionString="Data Source=(local);Initial Catalog=SignalRSamples;Integrated Security=SSPI;Asynchronous Processing=True;" />
    <add name="SignalRSamplesWithMARS" connectionString="Data Source=(local);Initial Catalog=SignalRSamples;Integrated Security=SSPI;Asynchronous Processing=True;MultipleActiveResultSets=true;" />
  </connectionStrings>
  <system.web>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5" />
  </system.web>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true" />
  </system.webServer>
  <system.diagnostics>
    <sources>
      <source name="SignalR.SqlMessageBus">
        <listeners>
          <add name="SignalR-Bus" />
        </listeners>
      </source>
     <source name="SignalR.ServiceBusMessageBus">
        <listeners>
            <add name="SignalR-Bus" />
        </listeners>
     </source>
     <source name="SignalR.ScaleoutMessageBus">
        <listeners>
            <add name="SignalR-Bus" />
        </listeners>
      </source>
      <source name="SignalR.Transports.WebSocketTransport">
        <listeners>
          <add name="SignalR-Transports" />
        </listeners>
      </source>
      <source name="SignalR.Transports.ServerSentEventsTransport">
          <listeners>
              <add name="SignalR-Transports" />
          </listeners>
      </source>
      <source name="SignalR.Transports.ForeverFrameTransport">
          <listeners>
              <add name="SignalR-Transports" />
          </listeners>
      </source>
      <source name="SignalR.Transports.LongPollingTransport">
        <listeners>
            <add name="SignalR-Transports" />
        </listeners>
      </source>
      <source name="SignalR.Transports.TransportHeartBeat">
        <listeners>
            <add name="SignalR-Transports" />
        </listeners>
      </source>
    </sources>
    <switches>
      <add name="SignalRSwitch" value="Verbose" />
    </switches>
    <sharedListeners>
      <add name="SignalR-Transports" 
           type="System.Diagnostics.TextWriterTraceListener" 
           initializeData="transports.log.txt" />
        <add name="SignalR-Bus"
           type="System.Diagnostics.TextWriterTraceListener"
           initializeData="bus.log.txt" />
    </sharedListeners>
    <trace autoflush="true" />
  </system.diagnostics>
  <entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
      <parameters>
        <parameter value="v11.0" />
      </parameters>
    </defaultConnectionFactory>
  </entityFramework>
</configuration>

Wenn Sie die Anwendung in Visual Studio ausführen, können Sie die Protokolle im Ausgabefenster anzeigen.

Aufrufen von Clientmethoden und Verwalten von Gruppen außerhalb der Hub-Klasse

Um Clientmethoden aus einer anderen Klasse als Ihrer Hub-Klasse aufzurufen, rufen Sie einen Verweis auf das SignalR-Kontextobjekt für den Hub ab, und verwenden Sie dieses, um Methoden auf dem Client aufzurufen oder Gruppen zu verwalten.

Die folgende Beispielklasse StockTicker ruft das Kontextobjekt ab, speichert es in einem instance der -Klasse, speichert die Klasse instance in einer statischen Eigenschaft und verwendet den Kontext der Singleton-Klasse instance, um die Methode auf Clients aufzurufen, die updateStockPrice mit einem Hub namens StockTickerHubverbunden sind.

// For the complete example, go to 
// http://www.asp.net/signalr/overview/signalr-1x/getting-started/tutorial-server-broadcast-with-aspnet-signalr
// This sample only shows code related to getting and using the SignalR context.
public class StockTicker
{
    // Singleton instance
    private readonly static Lazy<StockTicker> _instance = new Lazy<StockTicker>(
        () => new StockTicker(GlobalHost.ConnectionManager.GetHubContext<StockTickerHub>()));

    private IHubContext _context;

    private StockTicker(IHubContext context)
    {
        _context = context;
    }

    // This method is invoked by a Timer object.
    private void UpdateStockPrices(object state)
    {
        foreach (var stock in _stocks.Values)
        {
            if (TryUpdateStockPrice(stock))
            {
                _context.Clients.All.updateStockPrice(stock);
            }
        }
    }

Wenn Sie den Kontext in einem langlebigen Objekt mehrmals verwenden müssen, rufen Sie den Verweis einmal ab, und speichern Sie ihn, anstatt ihn jedes Mal erneut zu erhalten. Durch einmaliges Abrufen des Kontexts wird sichergestellt, dass SignalR Nachrichten an Clients in derselben Reihenfolge sendet, in der Ihre Hub-Methoden Clientmethodenaufrufe vornehmen. Ein Tutorial zur Verwendung des SignalR-Kontexts für einen Hub finden Sie unter Server Broadcast mit ASP.NET SignalR.

Aufrufen von Clientmethoden

Sie können angeben, welche Clients den RPC erhalten, aber Sie haben weniger Optionen als beim Aufrufen von einer Hubklasse. Der Grund dafür ist, dass der Kontext nicht einem bestimmten Aufruf von einem Client zugeordnet ist, sodass alle Methoden, die Kenntnisse der aktuellen Verbindungs-ID erfordern, wie Clients.Others, oder Clients.Calleroder Clients.OthersInGroup, nicht verfügbar sind. Die folgenden Optionen sind verfügbar:

  • Alle verbundenen Clients.

    context.Clients.All.addContosoChatMessageToPage(name, message);
    
  • Ein bestimmter Client, der durch die Verbindungs-ID identifiziert wird.

    context.Clients.Client(connectionID).addContosoChatMessageToPage(name, message);
    
  • Alle verbundenen Clients mit Ausnahme der angegebenen Clients, die durch die Verbindungs-ID identifiziert werden.

    context.Clients.AllExcept(connectionId1, connectionId2).addContosoChatMessageToPage(name, message);
    
  • Alle verbundenen Clients in einer angegebenen Gruppe.

    context.Clients.Group(groupName).addContosoChatMessageToPage(name, message);
    
  • Alle verbundenen Clients in einer angegebenen Gruppe mit Ausnahme der angegebenen Clients, die durch die Verbindungs-ID identifiziert werden.

    Clients.Group(groupName, connectionId1, connectionId2).addContosoChatMessageToPage(name, message);
    

Wenn Sie ihre Nicht-Hub-Klasse über Methoden in Ihrer Hub-Klasse aufrufen, können Sie die aktuelle Verbindungs-ID übergeben und diese mit Clients.Client, Clients.AllExceptoder Clients.Group verwenden, um , Clients.Othersoder Clients.OthersInGroupzu simulierenClients.Caller. Im folgenden Beispiel übergibt die MoveShapeHub -Klasse die Verbindungs-ID an die Broadcaster -Klasse, damit die Broadcaster -Klasse simulieren Clients.Otherskann.

// For the complete example, see
// http://www.asp.net/signalr/overview/getting-started/tutorial-high-frequency-realtime-with-signalr
// This sample only shows code that passes connection ID to the non-Hub class,
// in order to simulate Clients.Others.
public class MoveShapeHub : Hub
{
    // Code not shown puts a singleton instance of Broadcaster in this variable.
    private Broadcaster _broadcaster;

    public void UpdateModel(ShapeModel clientModel)
    {
        clientModel.LastUpdatedBy = Context.ConnectionId;
        // Update the shape model within our broadcaster
        _broadcaster.UpdateShape(clientModel);
    }
}

public class Broadcaster
{
    public Broadcaster()
    {
        _hubContext = GlobalHost.ConnectionManager.GetHubContext<MoveShapeHub>();
    }

    public void UpdateShape(ShapeModel clientModel)
    {
        _model = clientModel;
        _modelUpdated = true;
    }

    // Called by a Timer object.
    public void BroadcastShape(object state)
    {
        if (_modelUpdated)
        {
            _hubContext.Clients.AllExcept(_model.LastUpdatedBy).updateShape(_model);
            _modelUpdated = false;
        }
    }
}

Verwalten der Gruppenmitgliedschaft

Zum Verwalten von Gruppen haben Sie die gleichen Optionen wie in einer Hub-Klasse.

  • Hinzufügen eines Clients zu einer Gruppe

    context.Groups.Add(connectionID, groupName);
    
  • Entfernen eines Clients aus einer Gruppe

    context.Groups.Remove(connectionID, groupName);
    

Anpassen der Hubs-Pipeline

Mit SignalR können Sie Ihren eigenen Code in die Hubpipeline einfügen. Das folgende Beispiel zeigt ein benutzerdefiniertes Hubpipelinemodul, das jeden vom Client empfangenen eingehenden Methodenaufruf und ausgehenden Methodenaufruf protokolliert, der auf dem Client aufgerufen wird:

public class LoggingPipelineModule : HubPipelineModule 
{ 
    protected override bool OnBeforeIncoming(IHubIncomingInvokerContext context) 
    { 
        Debug.WriteLine("=> Invoking " + context.MethodDescriptor.Name + " on hub " + context.MethodDescriptor.Hub.Name); 
        return base.OnBeforeIncoming(context); 
    }   
    protected override bool OnBeforeOutgoing(IHubOutgoingInvokerContext context) 
    { 
        Debug.WriteLine("<= Invoking " + context.Invocation.Method + " on client hub " + context.Invocation.Hub); 
        return base.OnBeforeOutgoing(context); 
    } 
}

Der folgende Code in der Datei Global.asax registriert das Modul, das in der Hubpipeline ausgeführt werden soll:

protected void Application_Start(object sender, EventArgs e) 
{ 
    GlobalHost.HubPipeline.AddModule(new LoggingPipelineModule()); 
    RouteTable.Routes.MapHubs();
}

Es gibt viele verschiedene Methoden, die Sie überschreiben können. Eine vollständige Liste finden Sie unter HubPipelineModule-Methoden.