Condividi tramite


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 offrire funzionalità di messaggistica ad alta frequenza. In questo caso, la "messaggistica ad alta frequenza" indica che il server invia gli aggiornamenti a una frequenza 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 per corrispondere alla posizione della forma trascinata usando 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
  • Aggiungere un'animazione uniforme

Avviso

Questa documentazione non è per la versione più recente di SignalR. Esaminare ASP.NET Core SignalR.

Prerequisiti

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 vuota ASP.NET e aggiungere le librerie SignalR e jQuery.UI.

  1. In Visual Studio creare un'applicazione Web ASP.NET.

    Creare il Web

  2. Nella finestra Nuova applicazione Web ASP.NET - MoveShapeDemo lasciare vuoto selezionato e selezionare OK.

  3. In Esplora soluzioni fare clic con il pulsante destro del mouse sul progetto e scegliere Aggiungi>nuovo elemento.

  4. In Aggiungi nuovo elemento - MoveShapeDemo selezionare Installazione>di Visual C#>Web>SignalR e quindi selezionare Classe hub SignalR (v2) .

  5. Assegnare un nome alla classe MoveShapeHub e aggiungerlo al progetto.

    Questo passaggio crea il file di classe MoveShapeHub.cs . Contemporaneamente, aggiunge un set di file di script e riferimenti all'assembly che supportano SignalR al progetto.

  6. Fare clic su Strumenti>Gestione Pacchetti NuGet>Console di Gestione pacchetti.

  7. Nella console di Gestione pacchetti eseguire questo comando:

    Install-Package jQuery.UI.Combined
    

    Il comando installa la libreria dell'interfaccia utente jQuery. Lo si usa per animare la forma.

  8. In Esplora soluzioni espandere il nodo Script.

    Riferimenti alla libreria di 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 vengono fornite nelle sezioni successive.

  1. Aprire il file MoveShapeHub.cs .

  2. 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; }
        }
    }
    
  3. Salvare il file.

La MoveShapeHub classe è un'implementazione di un hub SignalR. Come nell'esercitazione Introduzione con 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. Queste coordinate vengono trasmesse a tutti gli altri client connessi. SignalR serializza automaticamente questo oggetto usando JSON.

L'app invia l'oggetto ShapeModel al client. Ha membri per archiviare la posizione della forma. La versione dell'oggetto nel server include anche un membro per tenere traccia dei dati del client archiviati. Questo oggetto impedisce al server di inviare nuovamente i dati di un client. Questo membro usa l'attributo JsonIgnore per mantenere l'applicazione dalla serializzazione dei dati e l'invio al client.

Eseguire il mapping all'hub all'avvio dell'app

Successivamente, si è configurato il mapping all'hub all'avvio dell'applicazione. In SignalR 2 aggiungere una classe di avvio OWIN crea il mapping.

  1. In Esplora soluzioni fare clic con il pulsante destro del mouse sul progetto e scegliere Aggiungi>nuovo elemento.

  2. In Aggiungi nuovo elemento - MoveShapeDemo selezionare Installa>Visual C#>Web e quindi selezionare Classe di avvio OWIN.

  3. Assegnare un nome alla classe Startup e selezionare OK.

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

  1. In Esplora soluzioni fare clic con il pulsante destro del mouse sul progetto e scegliere Aggiungi>pagina HTML.

  2. Assegnare un nome alla pagina Impostazione predefinita e selezionare OK.

  3. In Esplora soluzioni fare clic con il pulsante destro del mouse suDefault.html e scegliere Imposta come pagina iniziale.

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

  6. Aggiornare i riferimenti allo script nel blocco di codice per corrispondere alle versioni dei file di script nel progetto.

Questo codice HTML e JavaScript crea un rosso div denominato shape. Abilita il comportamento di trascinamento della forma usando 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, la forma si sposta anche negli altri browser.

  1. Nella barra degli strumenti attivare Debug script e quindi selezionare il pulsante Play per eseguire l'applicazione in modalità Debug.

    Screenshot dell'utente che attiva la modalità di debug e seleziona riproduzione.

    Viene visualizzata una finestra del browser con la forma rossa nell'angolo superiore destro.

  2. Copiare l'URL della pagina.

  3. Aprire un altro browser e incollare l'URL nella barra degli indirizzi.

  4. 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 al numero di messaggi inviati. Di conseguenza, i client e il server vengono sopraffatti con messaggi e prestazioni degradati. Inoltre, l'app visualizza un'animazione disgiunte nel client. Questa animazione a giro si verifica perché la forma viene spostata immediatamente da ogni metodo. È meglio se la forma si sposta senza problemi in ogni nuova posizione. Si apprenderà quindi 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 frequenza fissa. Questo ciclo è una rappresentazione di base di un "ciclo di gioco". È una funzione denominata ripetutamente che determina tutte le funzionalità di un gioco.

  1. 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 di nuovo 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 il moved flag indica che sono presenti nuovi dati di posizione da inviare.

  2. Selezionare il pulsante play per avviare l'applicazione

  3. Copiare l'URL della pagina.

  4. Aprire un altro browser e incollare l'URL nella barra degli indirizzi.

  5. 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 verrà visualizzata come uniforme in primo luogo.

Aggiungere il ciclo del server

Nell'applicazione corrente, i messaggi inviati dal server al client vengono visualizzati come vengono ricevuti. Questo traffico di rete presenta un problema simile visto nel client.

L'app può inviare messaggi più spesso rispetto alle esigenze. 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.

  1. 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; }
        }
        
    }
    
  2. Selezionare il pulsante Play per avviare l'applicazione.

  3. Copiare l'URL della pagina.

  4. Aprire un altro browser e incollare l'URL nella barra degli indirizzi.

  5. 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 da .NET Framework.

È consigliabile imparare che l'hub stesso è transitorio. Viene creato ogni volta che è necessario. Quindi l'app crea come Broadcaster singleton. Usa l'inizializzazione lazy per rinviare la creazione dell'oggetto Broadcasterfinché 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 fuori dal metodo dell'hub UpdateModel . Non viene più chiamato immediatamente ogni volta che l'app riceve messaggi in ingresso. L'app invia invece i messaggi ai client a una frequenza 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

Aggiungere un'animazione uniforme

L'applicazione è quasi completata, 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 animate libreria dell'interfaccia utente JQuery. Può spostare la forma in modo uniforme tra la sua posizione corrente e nuova.

  1. Aggiornare il metodo del client updateShape nel file Default.html per avere un aspetto 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>
    
  2. Selezionare il pulsante Play per avviare l'applicazione.

  3. Copiare l'URL della pagina.

  4. Aprire un altro browser e incollare l'URL nella barra degli indirizzi.

  5. Trascinare la forma in una delle finestre del browser.

Il movimento della forma nell'altra finestra viene visualizzato meno sgranato. L'app interpola il movimento nel tempo anziché essere impostato una sola volta per ogni messaggio in ingresso.

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

Il paradigma di comunicazione appena appreso è utile per lo sviluppo di giochi online e altre simulazioni, come il gioco ShootR creato con SignalR.

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
  • Eseguire l'app
  • Aggiunta del ciclo client
  • Aggiunta del ciclo del server
  • Aggiunta di animazioni fluide

Passare all'articolo successivo per informazioni su come creare un'applicazione Web che usa ASP.NET SignalR 2 per fornire funzionalità di trasmissione server.