Tutorial: Erstellen einer Hochfrequenz-Echtzeit-App mit SignalR 2

In diesem Tutorial wird gezeigt, wie Sie eine Webanwendung erstellen, die ASP.NET SignalR 2 verwendet, um hochfrequente Messagingfunktionen bereitzustellen. In diesem Fall bedeutet "Hochfrequenzmessaging", dass der Server Updates mit einer festen Rate sendet. Sie senden bis zu 10 Nachrichten pro Sekunde.

Die von Ihnen erstellte Anwendung zeigt eine Form an, die Benutzer ziehen können. Der Server aktualisiert die Position des Shapes in allen verbundenen Browsern so, dass sie mit zeitgesteuerten Updates der Position des gezogenen Shapes entspricht.

Die in diesem Tutorial vorgestellten Konzepte enthalten Anwendungen für Echtzeitspiele und andere Simulationsanwendungen.

In diesem Tutorial:

  • Einrichten des Projekts
  • Erstellen der Basisanwendung
  • Zuordnen zum Hub 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 gilt nicht für die neueste Version von SignalR. Sehen Sie sich ASP.NET Core SignalR an.

Voraussetzungen

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.

  1. Erstellen Sie in Visual Studio eine ASP.NET Webanwendung.

    Web erstellen

  2. Lassen Sie im Fenster Neue ASP.NET Webanwendung – MoveShapeDemodie Option Leer ausgewählt, und wählen Sie OK aus.

  3. Klicken Sie in Projektmappen-Explorer mit der rechten Maustaste auf das Projekt, und wählen SieNeues Elementhinzufügen> aus.

  4. Wählen Sie unter Neues Element hinzufügen – MoveShapeDemodie Option Installiertes>Visual C#>Web>SignalR und dann SignalR Hub-Klasse (v2) aus.

  5. Nennen Sie die Klasse MoveShapeHub , und fügen Sie sie dem Projekt hinzu.

    In diesem Schritt wird die MoveShapeHub.cs-Klassendatei erstellt. Gleichzeitig werden dem Projekt skriptdateien und Assemblyverweise hinzugefügt, die SignalR unterstützen.

  6. Klicken Sie auf Extras>NuGet-Paket-Manager>Paket-Manager-Konsole.

  7. Führen Sie in der Paket-Manager-Konsole den folgenden Befehl aus:

    Install-Package jQuery.UI.Combined
    

    Mit dem Befehl wird die jQuery-UI-Bibliothek installiert. Sie verwenden es, um die Form zu animieren.

  8. Erweitern Sie in Projektmappen-Explorer den Knoten Skripts.

    Skriptbibliotheksverweise

    Skriptbibliotheken für jQuery, jQueryUI und SignalR sind im Projekt sichtbar.

Erstellen der Basisanwendung

In diesem Abschnitt erstellen Sie eine Browseranwendung. Die App sendet den Speicherort 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.

  1. Öffnen Sie die Datei MoveShapeHub.cs .

  2. 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; }
        }
    }
    
  3. Speichern Sie die Datei .

Die MoveShapeHub -Klasse ist eine Implementierung eines SignalR-Hubs. Wie im Tutorial 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 gesendet. SignalR serialisiert dieses Objekt automatisch mithilfe von JSON.

Die App sendet das ShapeModel Objekt an den Client. Es verfügt über Elemente, um die Position des Shapes zu speichern. Die Version des Objekts auf dem Server verfügt auch über einen Member, um nachzuverfolgen, welche Clientdaten gespeichert werden. Dieses Objekt verhindert, dass der Server die Daten eines Clients zurück an sich selbst sendet. Dieses Element verwendet das JsonIgnore -Attribut, um zu hindern, dass die Anwendung die Daten serialisiert und an den Client zurück sendet.

Zuordnen zum Hub beim Starten der App

Als Nächstes richten Sie die Zuordnung zum Hub ein, wenn die Anwendung gestartet wird. In SignalR 2 erstellt das Hinzufügen einer OWIN-Startklasse die Zuordnung.

  1. Klicken Sie in Projektmappen-Explorer mit der rechten Maustaste auf das Projekt, und wählen SieNeues Elementhinzufügen> aus.

  2. Wählen Sie unter Neues Element hinzufügen – MoveShapeDemodie Option Installiertes>Visual C#>Web und dann OWIN-Startklasse aus.

  3. Nennen Sie die Klasse Startup , und wählen Sie OK aus.

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

  1. Klicken Sie in Projektmappen-Explorer mit der rechten Maustaste auf das Projekt, und wählen SieHTML-Seitehinzufügen> aus.

  2. Nennen Sie die Seite Standard, und wählen Sie OK aus.

  3. Klicken Sie in Projektmappen-Explorer mit der rechten Maustaste auf Default.html, und wählen Sie Als Startseite festlegen aus.

  4. Ersetzen Sie den Standardcode in der Default.html-Datei 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>
    
  5. Erweitern Sie in Projektmappen-ExplorerSkripts.

    Skriptbibliotheken für jQuery und SignalR sind im Projekt sichtbar.

    Wichtig

    Der Paket-Manager installiert eine höhere Version der SignalR-Skripts.

  6. Aktualisieren Sie die Skriptverweise im Codeblock so, dass sie den Versionen der Skriptdateien im Projekt entsprechen.

Mit diesem HTML- und JavaScript-Code wird ein Rot div namens shapeerstellt. Es aktiviert 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.

  1. Aktivieren Sie auf der Symbolleiste skriptdebuggen , und wählen Sie dann die Schaltfläche Wiedergabe aus, um die Anwendung im Debugmodus auszuführen.

    Screenshot: Benutzer, der den Debugmodus aktiviert und

    Ein Browserfenster mit der roten Form in der oberen rechten Ecke wird geöffnet.

  2. Kopieren Sie die URL der Seite.

  3. Öffnen Sie einen anderen Browser, und fügen Sie die URL in die Adressleiste ein.

  4. Ziehen Sie die Form in eines der Browserfenster. Die Form im anderen Browserfenster folgt.

Obwohl die Anwendungsfunktionen diese Methode verwenden, ist dies kein empfohlenes Programmiermodell. Es gibt keine Obergrenze für die Anzahl der gesendeten Nachrichten. Dies führt dazu, dass die Clients und der Server mit Nachrichten und Leistungseinbußen überlastet werden. Außerdem zeigt die App eine nicht zusammenhängende Animation auf dem Client an. Diese ruckartige Animation erfolgt, weil sich die Form sofort von jeder Methode bewegt. Es ist besser, wenn sich die Form reibungslos an jede neue Position bewegt. Als Nächstes erfahren Sie, wie Sie diese Probleme beheben.

Hinzufügen der Clientschleife

Das Senden der Position des Shapes bei jedem Mausbewegungsereignis führt zu einer unnötigen Menge an Netzwerkdatenverkehr. Die App muss die Nachrichten vom Client drosseln.

Verwenden Sie die Javascript-Funktion setInterval , um eine Schleife einzurichten, die neue Positionsinformationen mit einer festen Rate an den Server sendet. Diese Schleife ist eine grundlegende Darstellung einer "Spielschleife". Es ist eine wiederholt genannte Funktion, die die gesamte Funktionalität eines Spiels antreibt.

  1. Ersetzen Sie den Clientcode in der Default.html-Datei 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.

    Mit diesem neuen Code wird die updateServerModel Funktion hinzugefügt. Es wird mit einer festen Häufigkeit aufgerufen. Die Funktion sendet die Positionsdaten immer dann an den Server, wenn das moved Flag anzeigt, dass neue Positionsdaten gesendet werden.

  2. Wählen Sie die Wiedergabeschaltfläche aus, um die Anwendung zu starten.

  3. Kopieren Sie die URL der Seite.

  4. Öffnen Sie einen anderen Browser, und fügen Sie die URL in die Adressleiste ein.

  5. Ziehen Sie die Form in eines der Browserfenster. Die Form 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 werden nachrichten, die vom Server an den Client gesendet werden, so oft wie sie empfangen werden. Dieser Netzwerkdatenverkehr stellt ein ähnliches Problem wie auf dem Client dar.

Die App kann Nachrichten häufiger senden, als sie benötigt werden. Die Verbindung kann dadurch überschwemmt werden. In diesem Abschnitt wird beschrieben, wie Sie den Server aktualisieren, um einen Timer hinzuzufügen, der die Rate der ausgehenden Nachrichten drosselt.

  1. 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; }
        }
        
    }
    
  2. Wählen Sie die Wiedergabeschaltfläche aus, um die Anwendung zu starten.

  3. Kopieren Sie die URL der Seite.

  4. Öffnen Sie einen anderen Browser, und fügen Sie die URL in die Adressleiste ein.

  5. Ziehen Sie die Form in eines 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 dem .NET Framework.

Es ist gut zu erfahren, dass der Hub selbst transitorisch ist. Es wird jedes Mal erstellt, wenn es benötigt wird. Die App erstellt also als Broadcaster Singleton. Es verwendet die verzögerte Initialisierung, um die Erstellung der BroadcasterErstellung zu verzögern, bis sie benötigt wird. Dadurch wird sichergestellt, dass die App den ersten Hub instance vollständig erstellt, bevor der Timer gestartet wird.

Der Aufruf der Clientfunktion UpdateShape wird dann aus der -Methode des Hubs UpdateModel verschoben. Sie wird nicht mehr sofort aufgerufen, wenn die App eingehende Nachrichten empfängt. Stattdessen sendet die App die Nachrichten mit einer Rate von 25 Aufrufen pro Sekunde an die Clients. Der Prozess wird vom _broadcastLoop Timer innerhalb der Broadcaster -Klasse verwaltet.

Schließlich muss die -Klasse einen Verweis auf den derzeit ausgeführten _hubContext Hub abrufen, anstatt die Broadcaster Clientmethode direkt vom Hub aus aufzurufen. Es ruft den Verweis mit dem GlobalHostab.

Hinzufügen einer reibungslosen Animation

Die Anwendung ist fast fertig, aber wir könnten eine weitere Verbesserung vornehmen. Die App verschiebt die Form auf dem Client als Reaktion auf Servernachrichten. Verwenden Sie die Funktion der JQuery-UI-Bibliothek animate , anstatt die Position des Shapes auf den vom Server angegebenen neuen Speicherort festzulegen. Es kann das Shape reibungslos zwischen seiner aktuellen und neuen Position verschieben.

  1. 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>
    
  2. Wählen Sie die Wiedergabeschaltfläche aus, um die Anwendung zu starten.

  3. Kopieren Sie die URL der Seite.

  4. Öffnen Sie einen anderen Browser, und fügen Sie die URL in die Adressleiste ein.

  5. Ziehen Sie die Form in eines der Browserfenster.

Die Bewegung der Form im anderen Fenster erscheint weniger ruckartig. Die App interpoliert ihre Bewegung im Laufe der Zeit, anstatt einmal pro eingehender Nachricht festgelegt zu werden.

Dieser Code verschiebt die Form von der alten Position in die neue Position. Der Server gibt die Position der Form 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

Das Kommunikationsparadigma, über das Sie gerade gelernt haben, ist nützlich für die Entwicklung von Online-Spielen und anderen Simulationen, wie das mit SignalR erstellte ShootR-Spiel.

Weitere Informationen zu SignalR finden Sie in den folgenden Ressourcen:

Nächste Schritte

In diesem Tutorial:

  • Einrichten des Projekts
  • Erstellen der Basisanwendung
  • Beim Starten der App dem Hub zugeordnet
  • Client hinzugefügt
  • App ausgeführt
  • Clientschleife hinzugefügt
  • Serverschleife hinzugefügt
  • Glatte Animation hinzugefügt

Fahren Sie mit dem nächsten Artikel fort, um zu erfahren, wie Sie eine Webanwendung erstellen, die ASP.NET SignalR2 verwendet, um Serverübertragungsfunktionen bereitzustellen.