Mai 2018
Band 33, Nummer 5
Cutting Edge: Hinter den Kulissen von ASP.NET Core SignalR
Durch Dino Esposito
SignalR ist die letzte Hinzufügung der ASP.NET Core-Plattform und einen langen erwartet an, die an. Ich dare wird argumentiert, dass nur mit SignalR Bord wir wirklich starten können ASP.NET Core als bereit für Primzahlen für alle Anwendungstypen ansehen. Ohne eine asynchrone Benachrichtigung und Funktionen in Echtzeit ist kein schwerwiegendes Webanwendung heute möglich.
SignalR, die Sie, von ASP.NET kennen wurde vollständig umgeschrieben und befindet sich jetzt in der Familie von ASP.NET Core-Bibliotheken. In meinem letzten Monat (msdn.com/magazine/mt846469), ich einen kurzen Überblick über die Features und Funktionen von der neuen ASP.NET Core SignalR angeboten. In dieser Spalte werde ich mit der internen Maschinen beschäftigen.
SignalR ist eine Abstraktionsschicht für bidirektionale, bidirektionale von Remoteprozeduraufrufen (RPC) und über eine Vielzahl von Transportprotokollen funktioniert. Unabhängigkeit von der Host und nicht auf HTTP beschränkt ist. In der neuesten Version können sie Binärdaten und nicht nur JSON-basierten Nachrichten übertragen. Wenn SignalR für ASP.NET oder ASP.NET Core konfigurieren, können Sie das Transportprotokoll und der Message-Protokoll auswählen. Wenn Sie eine explizite Auswahl vornehmen, wird das Transportprotokoll wird automatisch ausgewählt und in den meisten Fällen es beläuft sich auf WebSockets. Das Message-Protokoll basiert dagegen auf JSON. Werfen wir einen Blick auf, was geschieht, wenn ein Client – beispielsweise einen Webclient – richtet eine Verbindung mit einem Serverendpunkt. Im folgenden Code wird eine Verbindung gestartet.
var progressConnection = new signalR.HubConnection("/progressDemo");
progressConnection.start();
Wenn Sie von diesen Code mit einem Tool wie Fiddler generierten Web-Datenverkehr überwachen, sehen Sie sich, dass zwei HTTP-Anforderungen gesendet werden. Abbildung 1 zeigt die Details der ersten Anforderung, die die Konversation gestartet wird.
Abbildung 1-Details der anfänglichen Starter-Anforderung
Die ursprüngliche Anforderung ist eine HTTP POST auf die SignalR-Route in Startklasse, gefolgt vom angegebenen ausgerichtet ist eine / Segment aushandeln. Der folgende Code zeigt, wie eine SignalR-Route definiert wird:
app.UseSignalR(routes =>
{
routes.MapHub<ProgressHub>("/progressDemo");
});
Basierend auf der Route, der erste Aufruf Ziel sind die URL: / Progressdemo/aushandeln.
Beachten Sie, dass in Vorschauversionen von SignalR-Verbs Optionen für diesen Zweck verwendet wurde. Der Endpunkt der SignalR-Server gibt ein JSON-Objekt, das wie folgt konfiguriert:
{
"connectionId" : "b6668ac0-1083-499f-870a-2a5376bf5047",
"availableTransports" : [
"WebSockets", "ServerSentEvents", "LongPolling"
]
}
Wie Sie sehen können, wird die JSON-Antwort enthält zwei Dinge: die eindeutige ID der Verbindung nur hergestellt und eine Liste der Transportprotokolle, die für die Verwendung verfügbar. Der Beispielcode gibt an, dass WebSockets, ServerSentEvents und LongPolling erhält die Client und Server-Konfiguration verwendet werden können. Was daraufhin geschieht, hängt von den Transport, die tatsächlich vom Client ausgewählt.
SignalR tendenziell WebSockets zu verwenden, wenn möglich. Wenn nicht der Fall, überprüft er die ServerSentEvents und fällt, die auf LongPolling zurück. Wenn WebSockets verwendet werden kann, wird eine HTTP GET-Anforderung auf dieselbe URL wie vor platziert. Dieses Mal fügt die Anforderung auch die Verbindungs-ID als ein Abfragezeichenfolgen-Parameter. Die GET-Anforderung ist tatsächlich eine Aktualisierung Protocol-Anforderung. Genauer gesagt, ist ein Protokoll-Upgrade eine normale HTTP-Anfrage (einen GET-Befehl jedoch auch einen Beitrag möglich) mit zwei ad-hoc-Header. Eine ist der Connection-Header, die zu aktualisierende festgelegt werden muss. Das andere ist Upgrades, die auf den Namen des Protokolls erforderliche muss festgelegt werden – in diesem Fall WebSockets. Wenn das Protokoll Upgrade akzeptiert wird, gibt der Server eine HTTP-101 wechseln Protokolle-Antwort zurück (siehe Abbildung 1).
Transportprotokolle
SignalR kann verschiedener Transportprotokolle nutzen. Der Client kann erzwingen, dass die Verbindung über ein bestimmtes Protokoll erfolgen, aber das Protokoll wird standardmäßig automatisch bestimmt. Um einen bestimmten Transport zu beantragen, fügen Sie einfach einen zusätzlichen Parameter, der JavaScript-Code (oder den Clientcode, wenn ein nicht-Client verwendet wird). Im Folgenden finden Sie ein Beispiel:
var progressConnection = new signalR.HubConnection(
"/progressDemo",
{transport : signalR.TransportType.WebSocket});
Beachten Sie, dass durch Übergeben eines Arrays anstelle eines direkten Namens wird die Auswahl einer der wenigen angegebenen Protokolle eingeschränkt werden kann. Natürlich unterscheiden sich Transportprotokolle, einige Aspekte zu erhalten. Abbildung 2 Hauptmerkmale des jedes Protokoll aufgeführt.
Abbildung 2 unterstützte Transportprotokolle
Protokoll | Beschreibung |
WebSockets | Basierend auf einer 1: 1-Verbindung zwischen dem Client und Server. Sowohl Client-als auch auf eine freigegebene Pipe so schreiben, dass der Fluss der Daten bidirektional ist. Das Protokoll kann nicht überall verwendet werden und wird vom Browser und für die Verbindung verwendeten Servertyp beschränkt. Auf dem Client ist ein moderner Browser erforderlich. Die neuesten Versionen von allen gängigen Browsern arbeiten in der Regel, mit Ausnahme von Internet Explorer vor Version 10. Windows 8 oder höher muss auf dem Server, wenn IIS oder HttpSysServer verwenden auf dem Client. |
ServerSentEvents | Basierend auf EventSource-Objekt auf dem Server aktiv. Das Objekt stellt eine Pipe, die den Server an den Client zu verbinden. Nachdem die Verbindung hergestellt wird, kann der Server Ereignisse kontinuierlich senden, während der Client nur über einfache AJAX-Aufrufe kommunizieren kann. Das Protokoll-Daten zurück in den Anfängen des Netscape und wird nicht auf das Internet Explorer oder Edge-Browser unterstützt. |
LongPolling | Das Protokoll funktioniert, indem eine Verbindung mit dem Server zur Verwendung für zukünftige Antworten öffnen. Die Verbindung bleibt ausstehend, bis eine Antwort gesendet wird, oder die Anforderung ein Timeout eintritt. In jedem Fall, sobald die Verbindung geschlossen wird, erneut, sodass der Client sofort es Abruf reicht ohne Unterbrechung Datenverkehr ist jedoch beschränkt, wie unbedingt erforderlich ist. Dieses Protokoll funktioniert mit allen Versionen von allen Browsern und wird als eine fallbacklösung betrachtet. |
Wenn die Kommunikation zwischen dem Web-Client und dem Server domänenübergreifende, der Server CORS aktiviert sein muss ist. In diesem Fall können Sie einem beliebigen verfügbaren Protokoll (Beachten Sie, dass JSONP in ASP.NET Core SignalR unterstützt wird):
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
}
Der Browser hinzugefügt die AJAX und WebSockets Aufrufe der ASP.NET Core SignalR Origin-Header. Darüber hinaus müssen Sie die CORS-Middleware, die in der SignalR-Anwendung, um sicherzustellen, dass der Browser Anforderungen ermöglicht konfiguriert haben.
Nachrichtenprotokolle
SignalR in ASP.NET immer serialisiert ausgetauschten Nachrichten, die mit dem textbasierten JSON-Format. Die neuesten ASP.NET Core SignalR Fügt eine binäre Nachrichtenprotokoll basierend auf dem MessagePack-Format. Dieses Format für die binäre Serialisierung können Sie Daten auf eine Weise sprachunabhängig die Weise, die JSON ausführt.
MessagePack ist kompakter und schneller als JSON übertragen und Paketgrößen von Funktionen, die noch mehr sind komprimieren als Binary JSON (BSON) – die MongoDB-optimierten Flavor von JSON. Bei MessagePack verbraucht Integer-Werten und NULL-Werte werden nur ein Byte an Daten. JSON NULL-Werte wird im Vergleich dazu 4 Bytes belegt. Weitere Informationen über das Protokoll Auschecken msgpack.org.
Um von einer ASP.NET Core SignalR-WebClient MessagePack zu verwenden, fügen Sie nur eine weitere Parameter an den JavaScript-Code, der Einrichtung der Verbindung wie hier gezeigt:
var protocol = new signalR.protocols.msgpack.MessagePackHubProtocol();
var progressConnection = new signalR.HubConnection(
"/progressDemo",
{
transport : signalR.TransportType.WebSocket,
protocol : protocol
}
);
Beachten Sie, dass im Fall von einem Webclient MessagePack verwenden möchte, Sie auch eine separate JavaScript-Datei (Signalr-msgpackprotocol.min.js) enthalten müssen, die Sie in der @aspnet/signalr NPM-Paket zu finden. MessagePack erfordert auch die ASP.NET Core-Server konfiguriert werden, wie folgt:
public void ConfigureServices(IServiceCollection services)
{
// SignalR already configured. Just add this:
services.AddMessagePackProtocol();
}
Bei Verwendung von einem Webclient alles, was Sie tun können, um MessagePack aktivieren müssen ist ein zusätzlicher Aufruf in der Clientanwendung. Insbesondere, platzieren Sie einen Aufruf der Erweiterungsmethode, dass WithMessagePackProtocol auf die Klasse HubConnectionBuilder definiert.
Nicht-Webclients
Die interessanteste Aspekt der .NET Standardspezifikation ist, dass Sie die gleiche Bibliothek aus, in eine Vielzahl von Clientanwendungen verwenden können, solange-API-Kompatibilität vorhanden ist. Die ASP.NET Core SignalR-Clientbibliothek wird basierend auf den standardmäßigen .NET 2.0 in jeglicher Clientanwendungen, die für eine Vielzahl von kompatible Plattformen, einschließlich Microsoft .NET Framework 4.6.1 kompiliert verwendet werden kann und höher. Dies bedeutet, dass, z. B. eine Windows Forms-Anwendung, die für neuere .NET Framework-Versionen kompiliert werden, als 4.6 stört die Dienste eines ASP.NET Core SignalR-Hubs nutzen können.
Beachten Sie wir finden Sie unter Gewusst wie: Starten Sie den langwierige Aufgabe, die im letzten Monat erläutert und Überwachen von innerhalb einer neuen Windows Forms-Anwendung. Verweisen Sie zunächst nach dem Erstellen der Anwendung rumpfdefinition ist das NuGet-Paket mit dem Namen Microsoft.AspNetCore.SignalR.Client und alle abhängigen Elemente, wie folgt:
private static HubConnection _connection;
private async void Form1_Load(object sender, EventArgs e)
{
_connection = new HubConnectionBuilder()
.WithUrl("http://localhost:60000/progressdemo")
.Build();
await _connection.StartAsync();
}
Der Code ausgeführt wird, wenn das Formular lädt und stellt die Verbindung mit dem angegebenen SignalR-Endpunkt her. Wenn Sie beabsichtigen ausgetauschten Daten mithilfe des Protokolls MessagePack serialisiert werden soll, fügen Sie eine weitere Zeile wie folgt den Konfigurationscode des Verbindungsobjekts-Generator hinzu:
private async void Form1_Load(object sender, EventArgs e)
{
_connection = new HubConnectionBuilder()
.WithUrl("http://localhost:60000/progressdemo")
.WithMessagePackProtocol()
.Build();
await _connection.StartAsync();
}
Das Verbindungsobjekt, das Sie erhalten muss weiter konfiguriert werden, mit der clientseitigen Handler verantwortlich für die Benutzeroberfläche zu aktualisieren, nachdem Benachrichtigungen vom Endpunkt ASP.NET Core SignalR zurückkehren. So sieht der Code aus:
_connection.On<int>("updateProgressBar", (perc) =>
{
this.Invoke(
(Action) (() => label1.Text = String.Format("{0}%", perc))
});
Wenn die UpdateProgressBar Benachrichtigung empfangen wird, wird eine textbezeichnung im Beispielcode mit den empfangenen Wert, der den Prozentsatz der derzeit ausgeführten Arbeit darstellt aktualisiert. Sie können so viele Handler als Sie müssen und die serverseitige SignalR-Entsprechung verfügbar gemacht haben. Abbildung 3 zeigt die vollständige neue Version der letzten Monatsspalte SignalR Back-End, wie ein Windows Forms-Client verbraucht werden würden.
Abbildung 3 die umgeschriebene SignalR-Back-End
_connection.On("initProgressBar", () =>
{
// Run on the UI thread
Invoke((Action)(() => label1.Text = "0%"));
});
_connection.On<int>("updateProgressBar", (perc) =>
{
// Run on the UI thread
Invoke((Action) (() => label1.Text = String.Format("{0}%", perc)));
});
_connection.On("clearProgressBar", () =>
{
// Run on the UI thread
Invoke((Action)(() =>
{
label1.Text = "100%";
button1.Enabled = true;
}));
});
await _connection.StartAsync();
Es gibt eine Reihe von Problemen, die Sie beim Schreiben von nicht - Web-SignalR Clients beachten sollten. Zuerst müssen die Client-Handler vollständig konfiguriert werden, wenn die Verbindung gestartet wird. Insbesondere wurden diese bedeutet, dass der Aufruf von StartAsync nach allen Vorkommen sollten die due Aufrufe an die Methode < T > vorgenommen.
Zweitens, Bedenken Sie, die nicht auf der Serverseite ausgeführt werden sollen – und teilweise länger andauernden – Vorgang, durch die SignalR im selben Windows-UI-Thread benachrichtigt wird. Die würde die Clientanwendung nicht reagierenden machen. Um das Problem zu umgehen, müssen Sie den serverseitigen Vorgang in einem anderen Thread, die hier gezeigten starten:
private void button1_Click(object sender, EventArgs e)
{
Task.Run(() =>
{
var client = new WebClient();
client.UploadString("http://localhost:60000/task/lengthy);
});
}
Anschließend, wenn die serverseitige SignalR-Hub wieder benachrichtigt, müssen aufgrund von Änderungen auf dem Hauptbenutzeroberflächen-Thread festgelegt werden, bevor sie stattfinden können. Dies erreichen mit der Invoke-Methode in der Client-Handler. Die Invoke-Methode ruft einen Delegaten ab, und es an den UI-Thread ausgeführt wird, wie hier gezeigt:
Invoke((Action)((perc) =>
{
label1.Text = String.Format("{0}%", perc);
}));
Abbildung 4 zeigt die Beispiel-Windows Forms-Anwendung in Aktion mit einer Bezeichnung, die der serverseitigen Vorgang Vorgangsfortschritts progressiv aktualisiert.
Abbildung 4 Windows Forms-Clientanwendung, die von einem ASP.NET Core SignalR-Hub aktualisiert
Die Windows Forms-Anwendung kann Benachrichtigungen über einen der unterstützten Ansätze: Broadcast, direktverbindung, Gruppen, einzelne Benutzer und streaming. Ich werde in einer zukünftigen Spalte dazu sagen aufweisen.
Zusammenfassung
SignalR für ASP.NET Core unterstützt die gleichen Transportprotokolle als die vorherige Version von ASP.NET, einschließlich WebSockets, ServerSentEvents und LongPolling. Darüber hinaus wird eine binäre Nachrichtenprotokoll zusätzlich zu den kanonischen JSON-Format unterstützt.
Wie sein Vorgänger ASP.NET Core SignalR aus einer Vielzahl von verschiedenen Clients aufgerufen werden können – einschließlich altmodisch Windows Forms-Anwendungen. Der Schlüssel zum Erreichen einer umfassenden Kompatibilität wird Unterstützung für die .NET Standard 2.0-Spezifikation. Wie wir den Artikel, wenn der Client eine Anwendung .NET Core ist nicht gesehen haben, müssen sie auf eine Version von .NET Framework kompiliert werden, die mit den neuesten Standard kompatibel ist. Die erforderliche Mindestversion ist .NET Framework 4.6.1.
Achten Sie darauf, dass Sie den Quellcode für diesen Artikel auschecken, das auf bit.ly/2FxCKTs.
Dino Esposito hat in seiner 25-jährigen Karriere mehr als 20 Bücher und 1.000 Artikel verfasst. Als Autor von „The Sabbatical Break“, einer theatralisch angehauchten Show, schreibt Esposito Software für eine grünere Welt als digitaler Stratege bei BaxEnergy. Folgen Sie ihm auf Twitter: @despos.
Unser Dank gilt dem folgenden Microsoft-Experten für die Durchsicht dieses Artikels: Andrew Stanton-Nurse