Share via


ASP.NET SignalR Hubs API Guide – Server (C#)

von Patrick Fletcher, Tom Dykstra

Warnung

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

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

Mit der SignalR Hubs-API können Sie Remoteprozeduraufrufe (Remoteprozeduraufrufe, RPCs) von einem Server an verbundene Clients und von Clients an den 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 kümmert sich um 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 finden Sie unter Einführung in SignalR 2.

In diesem Thema verwendete Softwareversionen

Themenversionen

Informationen zu früheren Versionen von SignalR finden Sie unter Ältere Versionen von SignalR.

Fragen und Kommentare

Bitte hinterlassen Sie Feedback dazu, wie Ihnen dieses Tutorial gefallen hat und was wir in den Kommentaren unten auf der Seite verbessern könnten. Wenn Sie Fragen haben, die nicht direkt mit dem Tutorial zusammenhängen, können Sie diese im ASP.NET SignalR-Forum oder StackOverflow.com posten.

Überblick

Dieses Dokument enthält folgende Abschnitte:

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

Die Serverkomponenten für SignalR 2 sind nur in .NET 4.5 verfügbar. Server, auf denen .NET 4.0 ausgeführt wird, müssen SignalR v1.x verwenden.

Registrieren der SignalR-Middleware

Um die Route zu definieren, die Clients zum Herstellen einer Verbindung mit Ihrem Hub verwenden, rufen Sie die MapSignalR -Methode auf, wenn die Anwendung gestartet wird. MapSignalR ist eine Erweiterungsmethode für die OwinExtensions -Klasse. Das folgende Beispiel zeigt, wie die SignalR Hubs-Route mithilfe einer OWIN-Startklasse definiert wird.

using Microsoft.Owin;
using Owin;

[assembly: OwinStartup(typeof(MyApplication.Startup))]
namespace MyApplication
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            // Any connection or hub wire up and configuration should go here
            app.MapSignalR();
        }

    }
}

Wenn Sie einer ASP.NET MVC-Anwendung SignalR-Funktionalität 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 2 und MVC 5.

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 – The generated proxy and what it does for you.)

Es kann außergewöhnliche Umstände geben, die diese Basis-URL für SignalR nicht nutzbar machen; Beispielsweise verfügen Sie über einen Ordner in Ihrem Projekt mit dem Namen Signalr , 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

app.MapSignalR("/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

Überladungen der MapSignalR -Methode ermöglichen es Ihnen, eine benutzerdefinierte URL, einen benutzerdefinierten Abhängigkeitslöser und die folgenden Optionen anzugeben:

  • Aktivieren Sie domänenübergreifende Aufrufe mithilfe von CORS oder JSONP von Browserclients.

    Wenn der Browser in der Regel eine Seite aus http://contoso.comlädt, befindet sich die SignalR-Verbindung in derselben Domäne unter http://contoso.com/signalr. Wenn die Seite von http://contoso.com eine Verbindung mit http://fabrikam.com/signalrherstellt, ist dies eine 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 ausführliche Fehlermeldungen.

    Wenn Fehler auftreten, besteht das Standardverhalten von SignalR darin, eine Benachrichtigungsnachricht ohne Details zu den Vorgängen an Clients zu senden. Das Senden detaillierter 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 als Antwort auf die URL "/signalr/hubs" eine JavaScript-Datei mit Proxys für Ihre Hub-Klassen generiert. Wenn Sie die JavaScript-Proxys nicht verwenden möchten oder 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-Leitfaden – JavaScript-Client – Erstellen einer physischen Datei für den von SignalR generierten Proxy.

Das folgende Beispiel zeigt, wie Die SignalR-Verbindungs-URL und diese Optionen in einem Aufruf der MapSignalR -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.EnableDetailedErrors = true;
hubConfiguration.EnableJavaScriptProxies = false;
app.MapSignalR("/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 async Task NewContosoChatMessage(string name, string message)
    {
        await 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 gesendet.

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 herstellt, die Verbindung trennt oder einen Methodenaufruf an den Server ausgibt.

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 für die 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 durch Instanziieren einer Hub-Klasse instance, sondern 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 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, sodass 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 Proxy

var contosoChatHubProxy = $.connection.contosoChatHub;

Wenn Sie einen anderen Namen für zu verwendende Clients angeben möchten, fügen Sie das HubName Attribut hinzu. Wenn Sie ein HubName Attribut verwenden, gibt es auf JavaScript-Clients keine Namensänderung in Kamelfall.

Server

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

JavaScript-Client mit generierten Proxy

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 zum Definieren aller Hubfunktionen in einer einzigen 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 die gleichen 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 – The generated proxy and what it does for you.

  • Gruppen werden innerhalb von Hubs definiert.

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

Strongly-Typed Hubs

Um eine Schnittstelle für Ihre Hubmethoden zu definieren, auf die Ihr Client verweisen kann (und Intellisense für Ihre Hubmethoden aktivieren kann), leiten Sie Ihren Hub von ( Hub<T> eingeführt in SignalR 2.1) ab und nicht Hub:

public class StrongHub : Hub<IClient>
{
    public async Task Send(string message)
    {
        await Clients.All.NewMessage(message);
    }
}

public interface IClient
{
    Task NewMessage(string message);
}

Definieren von Methoden in der Hub-Klasse, die von Clients aufgerufen werden 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 async Task NewContosoChatMessage(string name, string message)
    {
        await Clients.All.addNewMessageToPage(name, message);
    }
}
public class StockTickerHub : Hub
{
    public IEnumerable<Stock> GetAllStocks()
    {
        return _stockTicker.GetAllStocks();
    }
}

Sie können wie bei 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 Arrays von Objekten 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, sodass JavaScript-Code den JavaScript-Konventionen entsprechen kann.

Server

public void NewContosoChatMessage(string userName, string message)

JavaScript-Client mit generierten Proxy

contosoChatHubProxy.server.newContosoChatMessage(userName, message);

Wenn Sie einen anderen Namen für zu verwendende 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 Proxy

contosoChatHubProxy.server.PascalCaseNewContosoChatMessage(userName, message);

Wann asynchron ausgeführt werden soll

Wenn die Methode lange ausgeführt wird oder arbeiten muss, die mit Warten verbunden wären, z. B. eine Datenbanksuche oder ein Webdienstaufruf, machen Sie die Hub-Methode asynchron, indem Sie ein Task -Objekt (anstelle der Rückgabe) oder ein Task T-Objekt<> (anstelle des Tvoid Rückgabetyps) zurückgeben. Wenn Sie ein Task Objekt von der -Methode zurückgeben, wartet SignalR, bis der Task abgeschlossen ist, und sendet dann das ausgepackte Ergebnis zurück an den Client, sodass es keinen Unterschied in der Codeweise des Methodenaufrufs im Client gibt.

Wenn Sie eine Hub-Methode asynchron erstellen, wird verhindert, 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 selben Client blockiert, bis die Hub-Methode abgeschlossen ist.

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

Synchron

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

Asynchron

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 Proxy

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 Angeben 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.

Melden des Fortschritts von Hubmethodenaufrufen

SignalR 2.1 unterstützt das in .NET 4.5 eingeführte Statusberichtsmuster . Um die Fortschrittsberichterstattung zu implementieren, definieren Sie einen IProgress<T> Parameter für Ihre Hubmethode, auf den Ihr Client zugreifen kann:

public class ProgressHub : Hub
{
    public async Task<string> DoLongRunningThing(IProgress<int> progress)
    {
        for (int i = 0; i <= 100; i+=5)
        {
            await Task.Delay(200);
            progress.Report(i);
        }
        return "Job complete!";
    }
}

Beim Schreiben einer Servermethode mit langer Ausführungsdauer ist es wichtig, ein asynchrones Programmiermuster wie Async/Await zu verwenden, anstatt den Hubthread zu blockieren.

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 async Task NewContosoChatMessage(string name, string message)
    {
        await Clients.All.addNewMessageToPage(name, message);
    }
}

Das Aufrufen einer Clientmethode ist ein asynchroner Vorgang und gibt einen Taskzurück. Verwenden Sie await:

  • Um sicherzustellen, dass die Nachricht ohne Fehler gesendet wird.
  • So aktivieren Sie das Abfangen und Behandeln von Fehlern in einem Try-Catch-Block.

JavaScript-Client mit generierten Proxy

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 mit einem komplexen Objekt aufruft

public async Task SendMessage(string name, string message)
{
    await 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 Proxy

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);
    
  • Ein bestimmter Benutzer, der durch userId identifiziert wird.

    Clients.User(userid).addContosoChatMessageToPage(name, message);
    

    Standardmäßig ist IPrincipal.Identity.Namedies . Dies kann jedoch durch Registrieren einer Implementierung von IUserIdProvider beim globalen Host geändert werden.

  • Alle Clients und Gruppen in einer Liste von Verbindungs-IDs.

    Clients.Clients(ConnectionIds).broadcastMessage(name, message);
    
  • Eine Liste von Gruppen.

    Clients.Groups(GroupIds).broadcastMessage(name, message);
    
  • Ein Benutzer nach Name.

    Clients.Client(username).broadcastMessage(name, message);
    
  • Eine Liste von Benutzernamen (eingeführt in SignalR 2.1).

    Clients.Users(new string[] { "myUser", "myUser2" }).broadcastMessage(name, message);
    

Keine Kompilierzeitüberprüfung 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. Das folgende Codebeispiel zeigt, wie zwei Clientmethoden sequenziell ausgeführt werden.

Verwenden von Await (.NET 4.5)

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

Wenn Sie verwenden await , 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 async Task NewContosoChatMessage(string name, string message)
{
    string methodToCall = "addContosoChatMessageToPage";
    IClientProxy proxy = Clients.All;
    await 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. Tatsächlich 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 ihrer 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/Sub-Modell, und der Server verwaltet keine Listen von 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. Im folgenden Codebeispiel wird dies veranschaulicht.

Hinzufügen eines Clients zu einer Gruppe und anschließendes Messaging für diesen Client

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

Persistenz der Gruppenmitgliedschaft

SignalR verfolgt Verbindungen nach, nicht Benutzer. Wenn Sie also möchten, dass ein Benutzer 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 dann möglich, wenn die vorübergehende Unterbrechung das Ergebnis eines Serverneustarts oder -fehlers ist, da der Verbindungszustand für jeden Client, einschließlich Gruppenmitgliedschaften, auf den Client roundtriped 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 auftritt oder der Client die Verbindung trennt (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 aufrechtzuerhalten, wenn derselbe Benutzer eine neue Verbindung herstellt, muss Ihre Anwendung die Zuordnungen zwischen Benutzern und Gruppen nachverfolgen und 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 Ereignissen zur Verbindungslebensdauer 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, um dies zu tun.

  • Einzelbenutzergruppen.

    Sie können den Benutzernamen als Gruppennamen angeben und die aktuelle Verbindungs-ID der Gruppe jedes Mal hinzufügen, wenn der Benutzer eine Verbindung herstellt oder erneut eine Verbindung 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 Behandlung von Ereignissen für die Verbindungslebensdauer 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(bool stopCalled)
    {
        // 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(stopCalled);
    }

    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, d. h. SignalR führt die OnDisconnected Methode gefolgt von der OnConnected -Methode aus. SignalR erstellt immer eine neue Verbindungs-ID, wenn eine neue Verbindung hergestellt wird.

Die OnReconnected -Methode wird aufgerufen, wenn eine vorübergehende Verbindungsunterbrechung aufgetreten ist, von der SignalR automatisch wiederhergestellt werden kann, z. B. wenn ein Kabel vorübergehend getrennt und erneut verbunden wird, bevor das Verbindungstimen überschritten wird. Die OnDisconnected -Methode wird aufgerufen, wenn der Client getrennt wird und SignalR die Verbindung nicht automatisch wiederherstellen 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 geschaltet wird oder die App-Domäne die Wiederverwendung abgeschlossen hat, können einige Clients möglicherweise die Verbindung wiederherstellen und das OnReconnected Ereignis auslösen.

Weitere Informationen finden Sie unter Grundlegendes und Behandeln von Ereignissen zur Verbindungslebensdauer in SignalR.

Aufruferstatus nicht aufgefüllt

Die Methoden des Verbindungslebensdauer-Ereignishandlers werden vom Server aufgerufen. Dies bedeutet, dass jeder Zustand, den state Sie im -Objekt auf dem Client einfügen, nicht in der Caller -Eigenschaft auf dem Server aufgefüllt wird. Informationen zum Objekt und zur stateCaller 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

Verwenden Sie Context die -Eigenschaft der Hub-Klasse, um Informationen zum Client abzurufen. 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 über mehrere Hubs in Ihrer Anwendung verfügen.

  • 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 später hinzugefügt und Context.Headers aus Gründen der Abwärtskompatibilität beibehalten wurde.

  • Abfragen von Zeichenfolgendaten.

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

    Sie können auch Abfragezeichenfolgendaten aus Context.QueryStringabrufen.

    Die Abfragezeichenfolge, die Sie in dieser Eigenschaft erhalten, ist die Abfragezeichenfolge, die mit der HTTP-Anforderung verwendet wurde, die die SignalR-Verbindung hergestellt hat. Sie können Abfragezeichenfolgenparameter auf dem 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 .

    Die für die Verbindung verwendete Transportmethode finden Sie in den Abfragezeichenfolgendaten, zusammen mit einigen anderen Werten, 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 HttpContext -Objekt für die 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 bei jedem Methodenaufruf an den Server übertragen werden sollen. Auf dem Server können Sie auf diese Daten in der Clients.Caller Eigenschaft in Hubmethoden zugreifen, die von Clients aufgerufen werden. Die Clients.Caller -Eigenschaft wird für die Ereignishandlermethoden OnConnectedder Verbindungslebensdauer , OnDisconnectedund OnReconnectednicht aufgefü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 async Task NewContosoChatMessage(string data)
{
    string userName = Clients.Caller.userName;
    string computerName = Clients.Caller.computerName;
    await 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.

In VB.NET oder in einem stark typisierten Hub kann nicht über Clients.Callerauf das Aufruferzustandsobjekt zugegriffen werden; verwenden Sie Clients.CallerState stattdessen (eingeführt in SignalR 2.1):

Verwenden von CallerState in C#

public async Task NewContosoChatMessage(string data)
{
    string userName = Clients.CallerState.userName;
    string computerName = Clients.CallerState.computerName;
    await Clients.Others.addContosoChatMessageToPage(data, userName, computerName);
}

Verwenden von CallerState in Visual Basic

Public Async Function NewContosoChatMessage(message As String) As Task
    Dim userName As String = Clients.CallerState.userName
    Dim computerName As String = Clients.CallerState.computerName
    Await Clients.Others.addContosoChatMessageToPage(message, userName, computerName)
End Sub

Behandeln von Fehlern in der Hub-Klasse

Um Fehler zu behandeln, die in Ihren Hub-Klassenmethoden auftreten, stellen Sie zunächst sicher, dass Sie alle Ausnahmen von asynchronen Vorgängen (z. B. das Aufrufen von Clientmethoden) "beobachten", indem Sie verwenden await. Verwenden Sie dann eine oder mehrere der folgenden Methoden:

  • 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 Startup.cs, der das Modul in die Hubs-Pipeline einschleust.

    public class ErrorHandlingPipelineModule : HubPipelineModule
    {
        protected override void OnIncomingError(ExceptionContext exceptionContext, IHubIncomingInvokerContext invokerContext)
        {
            Debug.WriteLine("=> Exception " + exceptionContext.Error.Message);
            if (exceptionContext.Error.InnerException != null)
            {
                Debug.WriteLine("=> Inner Exception " + exceptionContext.Error.InnerException.Message);
            }
            base.OnIncomingError(exceptionContext, invokerContext);
    
        }
    }
    
    public void Configuration(IAppBuilder app)
    {
        // Any connection or hub wire up and configuration should go here
        GlobalHost.HubPipeline.AddModule(new ErrorHandlingPipelineModule()); 
        app.MapSignalR();
    }
    
  • Verwenden Sie die HubException -Klasse (eingeführt in SignalR 2). Dieser Fehler kann von jedem Hubaufruf ausgelöst werden. Der HubError Konstruktor akzeptiert eine Zeichenfolgenmeldung und ein Objekt zum Speichern zusätzlicher Fehlerdaten. SignalR serialisiert die Ausnahme automatisch und sendet sie an den Client, wo sie verwendet wird, um den Aufruf der Hubmethode abzulehnen oder fehlschlagen zu können.

    Die folgenden Codebeispiele veranschaulichen, wie ein HubException während eines Hubaufrufs ausgelöst wird und wie die Ausnahme auf JavaScript- und .NET-Clients behandelt wird.

    Servercode, der die HubException-Klasse veranschaulicht

    public class MyHub : Hub
    {
        public async Task Send(string message)
        {
            if(message.Contains("<script>"))
            {
                throw new HubException("This message will flow to the client", new { user = Context.User.Identity.Name, message = message });
            }
    
            await Clients.All.send(message);
        }
    }
    

    JavaScript-Clientcode, der die Antwort auf das Auslösen einer HubException in einem Hub veranschaulicht

    myHub.server.send("<script>")
                .fail(function (e) {
                    if (e.source === 'HubException') {
                        console.log(e.message + ' : ' + e.data.user);
                    }
                });
    

    .NET-Clientcode, der die Antwort auf das Auslösen einer HubException in einem Hub veranschaulicht

    try
    {
        await myHub.Invoke("Send", "<script>");
    }
    catch(HubException ex)
    {
        Console.WriteLine(ex.Message);
    }
    

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/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 empfangen, aber Sie haben weniger Optionen als beim Aufrufen von einer Hub-Klasse. Der Grund dafür ist, dass der Kontext nicht einem bestimmten Aufruf eines Clients zugeordnet ist, sodass alle Methoden, die Kenntnisse der aktuellen Verbindungs-ID erfordern, wie Clients.Othersz. B. , 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 von 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 , oder zu simulieren Clients.Caller, Clients.Othersoder Clients.OthersInGroup. 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/signalr-20/getting-started-with-signalr-20/tutorial-server-broadcast-with-signalr-20
// 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 dieselben 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 Hub-Pipelinemodul, 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 Startup.cs registriert das Modul für die Ausführung in der Hubpipeline:

public void Configuration(IAppBuilder app) 
{ 
    GlobalHost.HubPipeline.AddModule(new LoggingPipelineModule()); 
    app.MapSignalR();
}

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