Esercitazione: Creare un'app in tempo reale ad alta frequenza con SignalR 2
Questa esercitazione illustra come creare un'applicazione Web che usa ASP.NET SignalR 2 per fornire funzionalità di messaggistica ad alta frequenza. In questo caso, la "messaggistica ad alta frequenza" indica che il server invia gli aggiornamenti a una velocità fissa. Si inviano fino a 10 messaggi al secondo.
L'applicazione creata visualizza una forma che gli utenti possono trascinare. Il server aggiorna la posizione della forma in tutti i browser connessi in modo che corrisponda alla posizione della forma trascinata utilizzando gli aggiornamenti temporali.
I concetti introdotti in questa esercitazione includono applicazioni in giochi in tempo reale e altre applicazioni di simulazione.
In questa esercitazione:
- Configurare il progetto
- Creare l'applicazione di base
- Eseguire il mapping all'hub all'avvio dell'app
- Aggiungere il client
- Eseguire l'app
- Aggiungere il ciclo client
- Aggiungere il ciclo del server
- Aggiungi animazione fluida
Avviso
Questa documentazione non è per la versione più recente di SignalR. Esaminare ASP.NET Core SignalR.
Prerequisiti
- Visual Studio 2017 con il carico di lavoro Sviluppo ASP.NET e Web.
Configurare il progetto
In questa sezione viene creato il progetto in Visual Studio 2017.
Questa sezione illustra come usare Visual Studio 2017 per creare un'applicazione Web ASP.NET vuota e aggiungere le librerie SignalR e jQuery.UI.
In Visual Studio creare un'applicazione Web ASP.NET.
Nella finestra New ASP.NET Web Application - MoveShapeDemo (Nuova applicazione Web ASP.NET - MoveShapeDemo) lasciare vuota selezionata e selezionare OK.
In Esplora soluzioni fare clic con il pulsante destro del mouse sul progetto e scegliere Aggiungi>nuovo elemento.
In Aggiungi nuovo elemento - MoveShapeDemo selezionare Installato>Visual C#>Web>SignalR e quindi selezionare Classe hub SignalR (v2) .
Denominare la classe MoveShapeHub e aggiungerla al progetto.
Questo passaggio crea il file di classe MoveShapeHub.cs. Contemporaneamente, aggiunge un set di file di script e riferimenti ad assembly che supportano SignalR al progetto.
Fare clic su Strumenti>Gestione Pacchetti NuGet>Console di Gestione pacchetti.
Nella console di Gestione pacchetti eseguire questo comando:
Install-Package jQuery.UI.Combined
Il comando installa la libreria dell'interfaccia utente di jQuery. Usarlo per animare la forma.
In Esplora soluzioni espandere il nodo Script.
Le librerie di script per jQuery, jQueryUI e SignalR sono visibili nel progetto.
Creare l'applicazione di base
In questa sezione viene creata un'applicazione browser. L'app invia la posizione della forma al server durante ogni evento di spostamento del mouse. Il server trasmette queste informazioni a tutti gli altri client connessi in tempo reale. Altre informazioni su questa applicazione sono disponibili nelle sezioni successive.
Aprire il file MoveShapeHub.cs .
Sostituire il codice nel file MoveShapeHub.cs con questo codice:
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; } } }
Salvare il file.
La MoveShapeHub
classe è un'implementazione di un hub SignalR. Come nell'esercitazione Introduzione a SignalR , l'hub ha un metodo che i client chiamano direttamente. In questo caso, il client invia un oggetto con le nuove coordinate X e Y della forma al server. Tali coordinate vengono trasmesse a tutti gli altri client connessi. SignalR serializza automaticamente questo oggetto usando JSON.
L'app invia l'oggetto ShapeModel
al client. Dispone di membri per archiviare la posizione della forma. Anche la versione dell'oggetto nel server dispone di un membro per tenere traccia dei dati del client archiviati. Questo oggetto impedisce al server di inviare nuovamente i dati di un client a se stesso. Questo membro usa l'attributo JsonIgnore
per impedire all'applicazione di serializzare i dati e inviarli al client.
Eseguire il mapping all'hub all'avvio dell'app
Successivamente, si configura il mapping all'hub all'avvio dell'applicazione. In SignalR 2 aggiungere una classe di avvio OWIN crea il mapping.
In Esplora soluzioni fare clic con il pulsante destro del mouse sul progetto e scegliere Aggiungi>nuovo elemento.
In Aggiungi nuovo elemento - MoveShapeDemo selezionare Installato>Visual C#>Web e quindi selezionare Classe di avvio OWIN.
Assegnare alla classe il nome Startup e selezionare OK.
Sostituire il codice predefinito nel file Startup.cs con questo codice:
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(); } } }
La classe di avvio OWIN chiama MapSignalR
quando l'app esegue il Configuration
metodo . L'app aggiunge la classe al processo di avvio di OWIN usando l'attributo OwinStartup
assembly.
Aggiungere il client
Aggiungere la pagina HTML per il client.
In Esplora soluzioni fare clic con il pulsante destro del mouse sul progetto e scegliere Aggiungi>pagina HTML.
Assegnare alla pagina il nome Predefinito e selezionare OK.
In Esplora soluzioni fare clic con il pulsante destro del mouse su Default.html e scegliere Imposta come pagina iniziale.
Sostituire il codice predefinito nel file Default.html con questo codice:
<!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>
In Esplora soluzioni espandere Script.
Le librerie di script per jQuery e SignalR sono visibili nel progetto.
Importante
Gestione pacchetti installa una versione successiva degli script SignalR.
Aggiornare i riferimenti allo script nel blocco di codice in modo che corrispondano alle versioni dei file di script nel progetto.
Questo codice HTML e JavaScript crea un rosso div
denominato shape
. Consente il comportamento di trascinamento della forma tramite la libreria jQuery e usa l'evento drag
per inviare la posizione della forma al server.
Eseguire l'app
È possibile eseguire l'app per se'e funziona. Quando si trascina la forma intorno a una finestra del browser, anche la forma viene spostata negli altri browser.
Sulla barra degli strumenti attivare Debug script e quindi selezionare il pulsante Play per eseguire l'applicazione in modalità debug.
Viene visualizzata una finestra del browser con la forma rossa nell'angolo superiore destro.
Copiare l'URL della pagina.
Aprire un altro browser e incollare l'URL nella barra degli indirizzi.
Trascinare la forma in una delle finestre del browser. La forma nell'altra finestra del browser segue.
Anche se le funzioni dell'applicazione che usano questo metodo, non è un modello di programmazione consigliato. Non esiste alcun limite massimo per il numero di messaggi inviati. Di conseguenza, i client e il server vengono sovraccaricati con messaggi e prestazioni ridotte. Inoltre, l'app visualizza un'animazione non contigua nel client. Questa animazione cretina si verifica perché la forma si sposta immediatamente da ogni metodo. È meglio se la forma si sposta senza problemi in ogni nuova posizione. Successivamente, si apprenderà come risolvere questi problemi.
Aggiungere il ciclo client
L'invio della posizione della forma in ogni evento di spostamento del mouse crea una quantità non necessaria di traffico di rete. L'app deve limitare i messaggi dal client.
Usare la funzione javascript setInterval
per configurare un ciclo che invia nuove informazioni sulla posizione al server a una velocità fissa. Questo ciclo è una rappresentazione di base di un "ciclo di gioco". Si tratta di una funzione chiamata ripetutamente che determina tutte le funzionalità di un gioco.
Sostituire il codice client nel file Default.html con questo codice:
<!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>
Importante
È necessario sostituire nuovamente i riferimenti allo script. Devono corrispondere alle versioni degli script nel progetto.
Questo nuovo codice aggiunge la
updateServerModel
funzione . Viene chiamato su una frequenza fissa. La funzione invia i dati di posizione al server ogni volta che ilmoved
flag indica che sono presenti nuovi dati di posizione da inviare.Selezionare il pulsante Riproduci per avviare l'applicazione
Copiare l'URL della pagina.
Aprire un altro browser e incollare l'URL nella barra degli indirizzi.
Trascinare la forma in una delle finestre del browser. La forma nell'altra finestra del browser segue.
Poiché l'app limita il numero di messaggi inviati al server, l'animazione non viene visualizzata come uniforme all'inizio.
Aggiungere il ciclo del server
Nell'applicazione corrente, i messaggi inviati dal server al client escono con la frequenza con cui vengono ricevuti. Questo traffico di rete presenta un problema simile visualizzato nel client.
L'app può inviare messaggi più spesso di quanto siano necessari. La connessione può diventare inondata di conseguenza. Questa sezione descrive come aggiornare il server per aggiungere un timer che limita la frequenza dei messaggi in uscita.
Sostituire il contenuto di
MoveShapeHub.cs
con questo codice: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; } } }
Selezionare il pulsante play per avviare l'applicazione.
Copiare l'URL della pagina.
Aprire un altro browser e incollare l'URL nella barra degli indirizzi.
Trascinare la forma in una delle finestre del browser.
Questo codice espande il client per aggiungere la Broadcaster
classe . La nuova classe limita i messaggi in uscita usando la Timer
classe di .NET Framework.
È bene imparare che l'hub stesso è transitorio. Viene creato ogni volta che è necessario. L'app crea quindi come Broadcaster
singleton. Usa l'inizializzazione differita per rinviare la Broadcaster
creazione fino a quando non è necessaria. Ciò garantisce che l'app crei completamente la prima istanza dell'hub prima di avviare il timer.
La chiamata alla funzione dei UpdateShape
client viene quindi spostata all'esterno del metodo dell'hub UpdateModel
. Non viene più chiamato immediatamente ogni volta che l'app riceve i messaggi in arrivo. L'app invia invece i messaggi ai client a una velocità di 25 chiamate al secondo. Il processo viene gestito dal _broadcastLoop
timer dall'interno della Broadcaster
classe .
Infine, invece di chiamare direttamente il metodo client dall'hub, la Broadcaster
classe deve ottenere un riferimento all'hub operativo _hubContext
corrente. Ottiene il riferimento con .GlobalHost
Aggiungi animazione fluida
L'applicazione è quasi terminata, ma è possibile apportare un ulteriore miglioramento. L'app sposta la forma sul client in risposta ai messaggi del server. Anziché impostare la posizione della forma sulla nuova posizione specificata dal server, usare la funzione della libreria dell'interfaccia utente di animate
JQuery. Può spostare la forma senza problemi tra la posizione corrente e quella nuova.
Aggiornare il metodo del
updateShape
client nel file Default.html in modo che sia simile al codice evidenziato:<!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>
Selezionare il pulsante play per avviare l'applicazione.
Copiare l'URL della pagina.
Aprire un altro browser e incollare l'URL nella barra degli indirizzi.
Trascinare la forma in una delle finestre del browser.
Il movimento della forma nell'altra finestra appare meno sdollento. L'app esegue l'interpolazione del movimento nel tempo anziché essere impostata una sola volta per ogni messaggio in arrivo.
Questo codice sposta la forma dalla posizione precedente a quella nuova. Il server fornisce la posizione della forma nel corso dell'intervallo di animazione. In questo caso, si tratta di 100 millisecondi. L'app cancella qualsiasi animazione precedente in esecuzione sulla forma prima dell'avvio della nuova animazione.
Ottenere il codice
Scaricare il progetto completato
Risorse aggiuntive
Per altre informazioni su SignalR, vedere le risorse seguenti:
Passaggi successivi
In questa esercitazione:
- Configurare il progetto
- Creazione dell'applicazione di base
- Mappato all'hub all'avvio dell'app
- Aggiunta del client
- Esecuzione dell'app
- Aggiunta del ciclo client
- Aggiunta del ciclo del server
- Aggiunta di un'animazione fluida
Passare all'articolo successivo per informazioni su come creare un'applicazione Web che usa ASP.NET SignalR 2 per fornire funzionalità di trasmissione server.