Lernprogramm: Erstellen einer Hochfrequenz-Echtzeit-App mit SignalR 2
In diesem Lernprogramm wird gezeigt, wie Sie eine Webanwendung erstellen, die ASP.NET SignalR 2 verwendet, um Hochfrequenznachrichtenfunktionen bereitzustellen. In diesem Fall bedeutet "High-Frequency Messaging", dass der Server Updates mit fester Rate sendet. Sie senden bis zu 10 Nachrichten pro Sekunde.
Die von Ihnen erstellte Anwendung zeigt ein Shape an, das Benutzer ziehen können. Der Server aktualisiert die Position des Shapes in allen verbundenen Browsern, um die Position des gezogenen Shapes mithilfe zeitgesteuerter Aktualisierungen abzugleichen.
In diesem Lernprogramm eingeführte Konzepte enthalten Anwendungen in Echtzeitspielen und anderen Simulationsanwendungen.
In diesem Tutorial:
- Einrichten des Projekts
- Erstellen der Basisanwendung
- Zuordnen des Hubs beim Starten der App
- Hinzufügen des Clients
- Ausführen der App
- Hinzufügen der Clientschleife
- Hinzufügen der Serverschleife
- Hinzufügen einer reibungslosen Animation
Warnung
Diese Dokumentation ist nicht für die neueste Version von SignalR vorgesehen. Sehen Sie sich ASP.NET Core SignalR an.
Voraussetzungen
- Visual Studio 2017 mit der Workload ASP.NET und Webentwicklung
Einrichten des Projekts
In diesem Abschnitt erstellen Sie das Projekt in Visual Studio 2017.
In diesem Abschnitt wird gezeigt, wie Sie visual Studio 2017 verwenden, um eine leere ASP.NET Webanwendung zu erstellen und die SignalR- und jQuery.UI-Bibliotheken hinzuzufügen.
Erstellen Sie in Visual Studio eine ASP.NET Webanwendung.
Lassen Sie im Fenster "New ASP.NET Web Application - MoveShapeDemo" die Option "Leer" und wählen Sie "OK" aus.
Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt, und wählen Sie Hinzufügen>Neues Element aus.
Wählen Sie unter "Neues Element hinzufügen – MoveShapeDemo" die Option "Visual C#>Web>SignalR">und dann "SignalR Hub-Klasse (v2)" aus.
Benennen Sie die Klasse MoveShapeHub , und fügen Sie sie dem Projekt hinzu.
In diesem Schritt wird die MoveShapeHub.cs Klassendatei erstellt. Gleichzeitig fügt es eine Reihe von Skriptdateien und Assemblyverweise hinzu, die SignalR zum Projekt unterstützen.
Klicken Sie auf Extras>NuGet-Paket-Manager>Paket-Manager-Konsole.
Führen Sie in Paket-Manager Konsole den folgenden Befehl aus:
Install-Package jQuery.UI.Combined
Der Befehl installiert die jQuery UI-Bibliothek. Sie verwenden es, um die Form zu animieren.
Erweitern Sie in Projektmappen-Explorer den Knoten "Skripts".
Skriptbibliotheken für jQuery, jQueryUI und SignalR sind im Projekt sichtbar.
Erstellen der Basisanwendung
In diesem Abschnitt erstellen Sie eine Browseranwendung. Die App sendet die Position des Shapes während jedes Mausbewegungsereignisses an den Server. Der Server sendet diese Informationen in Echtzeit an alle anderen verbundenen Clients. Weitere Informationen zu dieser Anwendung finden Sie in späteren Abschnitten.
Öffnen Sie die datei MoveShapeHub.cs .
Ersetzen Sie den Code in der datei MoveShapeHub.cs durch diesen Code:
using Microsoft.AspNet.SignalR; using Newtonsoft.Json; namespace MoveShapeDemo { public class MoveShapeHub : Hub { public void UpdateModel(ShapeModel clientModel) { clientModel.LastUpdatedBy = Context.ConnectionId; // Update the shape model within our broadcaster Clients.AllExcept(clientModel.LastUpdatedBy).updateShape(clientModel); } } public class ShapeModel { // We declare Left and Top as lowercase with // JsonProperty to sync the client and server models [JsonProperty("left")] public double Left { get; set; } [JsonProperty("top")] public double Top { get; set; } // We don't want the client to get the "LastUpdatedBy" property [JsonIgnore] public string LastUpdatedBy { get; set; } } }
Speichern Sie die Datei .
Die MoveShapeHub
Klasse ist eine Implementierung eines SignalR-Hubs. Wie im Lernprogramm "Erste Schritte mit SignalR " verfügt der Hub über eine Methode, die die Clients direkt aufrufen. In diesem Fall sendet der Client ein Objekt mit den neuen X- und Y-Koordinaten des Shapes an den Server. Diese Koordinaten werden an alle anderen verbundenen Clients übertragen. SignalR serialisiert dieses Objekt automatisch mithilfe von JSON.
Die App sendet das ShapeModel
Objekt an den Client. Es verfügt über Member, um die Position des Shapes zu speichern. Die Version des Objekts auf dem Server verfügt auch über ein Element, um nachzuverfolgen, welche Clientdaten gespeichert werden. Dieses Objekt verhindert, dass der Server die Daten eines Clients an sich zurücksendet. Dieses Element verwendet das JsonIgnore
Attribut, um die Anwendung daran zu hindern, die Daten zu serialisieren und an den Client zurückzusenden.
Zuordnen des Hubs beim Starten der App
Als Nächstes richten Sie die Zuordnung zum Hub ein, wenn die Anwendung gestartet wird. Beim Hinzufügen einer OWIN-Startklasse in SignalR 2 wird die Zuordnung erstellt.
Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt, und wählen Sie Hinzufügen>Neues Element aus.
Wählen Sie in "Neues Element hinzufügen " MoveShapeDemo" die Option "Visual C#>Web installiert>" und dann "OWIN-Startklasse" aus.
Benennen Sie den Kursstart, und wählen Sie "OK" aus.
Ersetzen Sie den Standardcode in der datei Startup.cs durch diesen Code:
using Microsoft.Owin; using Owin; [assembly: OwinStartup(typeof(MoveShapeDemo.Startup))] namespace MoveShapeDemo { public class Startup { public void Configuration(IAppBuilder app) { // Any connection or hub wire up and configuration should go here app.MapSignalR(); } } }
Die OWIN-Startklasse ruft auf MapSignalR
, wenn die App die Configuration
Methode ausführt. Die App fügt die Klasse dem Startprozess von OWIN mithilfe des OwinStartup
Assembly-Attributs hinzu.
Hinzufügen des Clients
Fügen Sie die HTML-Seite für den Client hinzu.
Klicken Sie in Projektmappen-Explorer mit der rechten Maustaste auf das Projekt, und wählen Sie "HTML-Seite hinzufügen">aus.
Benennen Sie die Seite "Standard", und wählen Sie "OK" aus.
Klicken Sie in Projektmappen-Explorer mit der rechten Maustaste auf Default.html, und wählen Sie "Als Startseite festlegen" aus.
Ersetzen Sie den Standardcode in der datei Default.html durch diesen Code:
<!DOCTYPE html> <html> <head> <title>SignalR MoveShape Demo</title> <style> #shape { width: 100px; height: 100px; background-color: #FF0000; } </style> </head> <body> <script src="Scripts/jquery-1.10.2.min.js"></script> <script src="Scripts/jquery-ui-1.10.4.min.js"></script> <script src="Scripts/jquery.signalR-2.1.0.js"></script> <script src="/signalr/hubs"></script> <script> $(function () { var moveShapeHub = $.connection.moveShapeHub, $shape = $("#shape"), shapeModel = { left: 0, top: 0 }; moveShapeHub.client.updateShape = function (model) { shapeModel = model; $shape.css({ left: model.left, top: model.top }); }; $.connection.hub.start().done(function () { $shape.draggable({ drag: function () { shapeModel = $shape.offset(); moveShapeHub.server.updateModel(shapeModel); } }); }); }); </script> <div id="shape" /> </body> </html>
Erweitern Sie in Projektmappen-Explorer Skripts.
Skriptbibliotheken für jQuery und SignalR sind im Projekt sichtbar.
Wichtig
Der Paket-Manager installiert eine höhere Version der SignalR-Skripts.
Aktualisieren Sie die Skriptverweise im Codeblock so, dass sie den Versionen der Skriptdateien im Projekt entsprechen.
Dieser HTML- und JavaScript-Code erstellt einen roten div
Namen shape
. Es ermöglicht das Ziehverhalten des Shapes mithilfe der jQuery-Bibliothek und verwendet das drag
Ereignis, um die Position des Shapes an den Server zu senden.
Ausführen der App
Sie können die App ausführen, damit sie funktioniert. Wenn Sie das Shape um ein Browserfenster ziehen, wird das Shape auch in den anderen Browsern verschoben.
Aktivieren Sie in der Symbolleiste das Skriptdebugging , und wählen Sie dann die Wiedergabeschaltfläche aus, um die Anwendung im Debugmodus auszuführen.
Ein Browserfenster wird mit der roten Form in der oberen rechten Ecke geöffnet.
Kopieren Sie die URL der Seite.
Öffnen Sie einen anderen Browser, und fügen Sie die URL in die Adressleiste ein.
Ziehen Sie das Shape in einem der Browserfenster. Das Shape im anderen Browserfenster folgt.
Während die Anwendungsfunktionen diese Methode verwenden, ist es kein empfohlenes Programmiermodell. Es gibt keine Obergrenze für die Anzahl der gesendeten Nachrichten. Daher werden die Clients und der Server mit Nachrichten und Leistungseinbußen überfordert. Außerdem zeigt die App eine nicht zusammenhängende Animation auf dem Client an. Diese jerky Animation geschieht, da die Form sofort von jeder Methode verschoben wird. Es ist besser, wenn das Shape reibungslos an jede neue Position verschoben wird. Als Nächstes erfahren Sie, wie Sie diese Probleme beheben.
Hinzufügen der Clientschleife
Durch das Senden der Position des Shapes bei jedem Mausverschiebungsereignis wird ein unnötiger Netzwerkdatenverkehr erzeugt. Die App muss die Nachrichten vom Client drosseln.
Verwenden Sie die Javascript-Funktion setInterval
, um eine Schleife einzurichten, die neue Positionsinformationen zu einem festen Satz an den Server sendet. Diese Schleife ist eine grundlegende Darstellung einer "Spielschleife". Es ist eine wiederholt aufgerufene Funktion, die alle Funktionen eines Spiels steuert.
Ersetzen Sie den Clientcode in der datei Default.html durch diesen Code:
<!DOCTYPE html> <html> <head> <title>SignalR MoveShape Demo</title> <style> #shape { width: 100px; height: 100px; background-color: #FF0000; } </style> </head> <body> <script src="Scripts/jquery-1.10.2.min.js"></script> <script src="Scripts/jquery-ui-1.10.4.min.js"></script> <script src="Scripts/jquery.signalR-2.1.0.js"></script> <script src="/signalr/hubs"></script> <script> $(function () { var moveShapeHub = $.connection.moveShapeHub, $shape = $("#shape"), // Send a maximum of 10 messages per second // (mouse movements trigger a lot of messages) messageFrequency = 10, // Determine how often to send messages in // time to abide by the messageFrequency updateRate = 1000 / messageFrequency, shapeModel = { left: 0, top: 0 }, moved = false; moveShapeHub.client.updateShape = function (model) { shapeModel = model; $shape.css({ left: model.left, top: model.top }); }; $.connection.hub.start().done(function () { $shape.draggable({ drag: function () { shapeModel = $shape.offset(); moved = true; } }); // Start the client side server update interval setInterval(updateServerModel, updateRate); }); function updateServerModel() { // Only update server if we have a new movement if (moved) { moveShapeHub.server.updateModel(shapeModel); moved = false; } } }); </script> <div id="shape" /> </body> </html>
Wichtig
Sie müssen die Skriptverweise erneut ersetzen. Sie müssen mit den Versionen der Skripts im Projekt übereinstimmen.
Dieser neue Code fügt die
updateServerModel
Funktion hinzu. Es wird für eine feste Häufigkeit aufgerufen. Die Funktion sendet die Positionsdaten immer dann an den Server, wenn dasmoved
Flag angibt, dass neue Positionsdaten gesendet werden sollen.Wählen Sie die Wiedergabeschaltfläche aus, um die Anwendung zu starten.
Kopieren Sie die URL der Seite.
Öffnen Sie einen anderen Browser, und fügen Sie die URL in die Adressleiste ein.
Ziehen Sie das Shape in einem der Browserfenster. Das Shape im anderen Browserfenster folgt.
Da die App die Anzahl der nachrichten, die an den Server gesendet werden, drosselt, wird die Animation zunächst nicht so reibungslos angezeigt.
Hinzufügen der Serverschleife
In der aktuellen Anwendung gehen nachrichten, die vom Server an den Client gesendet werden, so oft wie sie empfangen werden. Dieser Netzwerkdatenverkehr stellt ein ähnliches Problem dar, wie wir auf dem Client sehen.
Die App kann Nachrichten häufiger senden, als sie benötigt werden. Die Verbindung kann dadurch überflutet werden. In diesem Abschnitt wird beschrieben, wie Sie den Server aktualisieren, um einen Timer hinzuzufügen, der die Rate der ausgehenden Nachrichten drosselt.
Ersetzen Sie den Inhalt von
MoveShapeHub.cs
durch den folgenden Code:using System; using System.Threading; using Microsoft.AspNet.SignalR; using Newtonsoft.Json; namespace MoveShapeDemo { public class Broadcaster { private readonly static Lazy<Broadcaster> _instance = new Lazy<Broadcaster>(() => new Broadcaster()); // We're going to broadcast to all clients a maximum of 25 times per second private readonly TimeSpan BroadcastInterval = TimeSpan.FromMilliseconds(40); private readonly IHubContext _hubContext; private Timer _broadcastLoop; private ShapeModel _model; private bool _modelUpdated; public Broadcaster() { // Save our hub context so we can easily use it // to send to its connected clients _hubContext = GlobalHost.ConnectionManager.GetHubContext<MoveShapeHub>(); _model = new ShapeModel(); _modelUpdated = false; // Start the broadcast loop _broadcastLoop = new Timer( BroadcastShape, null, BroadcastInterval, BroadcastInterval); } public void BroadcastShape(object state) { // No need to send anything if our model hasn't changed if (_modelUpdated) { // This is how we can access the Clients property // in a static hub method or outside of the hub entirely _hubContext.Clients.AllExcept(_model.LastUpdatedBy).updateShape(_model); _modelUpdated = false; } } public void UpdateShape(ShapeModel clientModel) { _model = clientModel; _modelUpdated = true; } public static Broadcaster Instance { get { return _instance.Value; } } } public class MoveShapeHub : Hub { // Is set via the constructor on each creation private Broadcaster _broadcaster; public MoveShapeHub() : this(Broadcaster.Instance) { } public MoveShapeHub(Broadcaster broadcaster) { _broadcaster = broadcaster; } public void UpdateModel(ShapeModel clientModel) { clientModel.LastUpdatedBy = Context.ConnectionId; // Update the shape model within our broadcaster _broadcaster.UpdateShape(clientModel); } } public class ShapeModel { // We declare Left and Top as lowercase with // JsonProperty to sync the client and server models [JsonProperty("left")] public double Left { get; set; } [JsonProperty("top")] public double Top { get; set; } // We don't want the client to get the "LastUpdatedBy" property [JsonIgnore] public string LastUpdatedBy { get; set; } } }
Wählen Sie die Wiedergabeschaltfläche aus, um die Anwendung zu starten.
Kopieren Sie die URL der Seite.
Öffnen Sie einen anderen Browser, und fügen Sie die URL in die Adressleiste ein.
Ziehen Sie das Shape in einem der Browserfenster.
Dieser Code erweitert den Client, um die Broadcaster
Klasse hinzuzufügen. Die neue Klasse drosselt die ausgehenden Nachrichten mithilfe der Timer
Klasse aus .NET Framework.
Es ist gut zu lernen, dass der Hub selbst transitoriert ist. Es wird jedes Mal erstellt, wenn es benötigt wird. Die App erstellt die Broadcaster
App also als Singleton. Es verwendet faule Initialisierung, um die Erstellung der Broadcaster
Erstellung zurückstellen, bis sie benötigt wird. Dadurch wird sichergestellt, dass die App die erste Hubinstanz vollständig erstellt, bevor sie den Timer startet.
Der Aufruf der Clientfunktion UpdateShape
wird dann aus der Hubmethode UpdateModel
verschoben. Er wird nicht mehr sofort aufgerufen, wenn die App eingehende Nachrichten empfängt. Stattdessen sendet die App die Nachrichten mit einer Rate von 25 Anrufen pro Sekunde an die Clients. Der Prozess wird vom _broadcastLoop
Timer innerhalb der Broadcaster
Klasse verwaltet.
Schließlich muss die Broadcaster
Klasse statt der Clientmethode direkt vom Hub aus einen Verweis auf den derzeit ausgeführten _hubContext
Hub abrufen. Er ruft den Verweis mit der GlobalHost
.
Hinzufügen einer reibungslosen Animation
Die Anwendung ist fast fertig, aber wir könnten eine weitere Verbesserung vornehmen. Die App verschiebt das Shape auf dem Client als Reaktion auf Servernachrichten. Anstatt die Position des Shapes auf die neue Position des Servers festzulegen, verwenden Sie die Funktion der JQuery UI-Bibliothek animate
. Es kann die Form reibungslos zwischen der aktuellen und der neuen Position verschieben.
Aktualisieren Sie die Methode des
updateShape
Clients in der Default.html-Datei so, dass sie wie der hervorgehobene Code aussieht:<!DOCTYPE html> <html> <head> <title>SignalR MoveShape Demo</title> <style> #shape { width: 100px; height: 100px; background-color: #FF0000; } </style> </head> <body> <script src="Scripts/jquery-1.10.2.min.js"></script> <script src="Scripts/jquery-ui-1.10.4.min.js"></script> <script src="Scripts/jquery.signalR-2.1.0.js"></script> <script src="/signalr/hubs"></script> <script> $(function () { var moveShapeHub = $.connection.moveShapeHub, $shape = $("#shape"), // Send a maximum of 10 messages per second // (mouse movements trigger a lot of messages) messageFrequency = 10, // Determine how often to send messages in // time to abide by the messageFrequency updateRate = 1000 / messageFrequency, shapeModel = { left: 0, top: 0 }, moved = false; moveShapeHub.client.updateShape = function (model) { shapeModel = model; // Gradually move the shape towards the new location (interpolate) // The updateRate is used as the duration because by the time // we get to the next location we want to be at the "last" location // We also clear the animation queue so that we start a new // animation and don't lag behind. $shape.animate(shapeModel, { duration: updateRate, queue: false }); }; $.connection.hub.start().done(function () { $shape.draggable({ drag: function () { shapeModel = $shape.offset(); moved = true; } }); // Start the client side server update interval setInterval(updateServerModel, updateRate); }); function updateServerModel() { // Only update server if we have a new movement if (moved) { moveShapeHub.server.updateModel(shapeModel); moved = false; } } }); </script> <div id="shape" /> </body> </html>
Wählen Sie die Wiedergabeschaltfläche aus, um die Anwendung zu starten.
Kopieren Sie die URL der Seite.
Öffnen Sie einen anderen Browser, und fügen Sie die URL in die Adressleiste ein.
Ziehen Sie das Shape in einem der Browserfenster.
Die Bewegung der Form im anderen Fenster erscheint weniger jerky. Die App interpoliert ihre Bewegung im Laufe der Zeit, anstatt einmal pro eingehende Nachricht festgelegt zu werden.
Dieser Code verschiebt das Shape von der alten Position in die neue. Der Server gibt die Position des Shapes im Verlauf des Animationsintervalls an. In diesem Fall sind das 100 Millisekunden. Die App löscht alle vorherigen Animationen, die auf dem Shape ausgeführt werden, bevor die neue Animation gestartet wird.
Abrufen des Codes
Abgeschlossenes Projekt herunterladen
Zusätzliche Ressourcen
Weitere Informationen zu SignalR finden Sie in den folgenden Ressourcen:
Nächste Schritte
In diesem Tutorial haben Sie:
- Einrichten des Projekts
- Erstellen der Basisanwendung
- Beim Starten der App dem Hub zugeordnet
- Client hinzugefügt
- Führen Sie die App aus
- Clientschleife hinzugefügt
- Serverschleife hinzugefügt
- Flüssige Animation hinzugefügt
Wechseln Sie zum nächsten Artikel, um zu erfahren, wie Sie eine Webanwendung erstellen, die ASP.NET SignalR 2 verwendet, um Serverübertragungsfunktionen bereitzustellen.