Tutoriel : Créer une application en temps réel haute fréquence avec SignalR 2

Ce tutoriel montre comment créer une application web qui utilise ASP.NET SignalR 2 pour fournir des fonctionnalités de messagerie haute fréquence. Dans ce cas, la « messagerie à fréquence élevée » signifie que le serveur envoie des mises à jour à un débit fixe. Vous envoyez jusqu’à 10 messages par seconde.

L’application que vous créez affiche une forme que les utilisateurs peuvent faire glisser. Le serveur met à jour la position de la forme dans tous les navigateurs connectés pour qu’elle corresponde à la position de la forme déplacée à l’aide de mises à jour chronologiques.

Les concepts présentés dans ce tutoriel ont des applications dans les jeux en temps réel et d’autres applications de simulation.

Dans ce tutoriel, vous allez :

  • Configuration du projet
  • Créer l’application de base
  • Mapper au hub au démarrage de l’application
  • Ajouter le client
  • Exécuter l’application
  • Ajouter la boucle cliente
  • Ajouter la boucle du serveur
  • Ajouter une animation fluide

Avertissement

Cette documentation ne concerne pas la dernière version de SignalR. Jetez un coup d’œil à ASP.NET Core SignalR.

Prérequis

Configuration du projet

Dans cette section, vous allez créer le projet dans Visual Studio 2017.

Cette section montre comment utiliser Visual Studio 2017 pour créer une application web ASP.NET vide et ajouter les bibliothèques SignalR et jQuery.UI.

  1. Dans Visual Studio, créez une application web ASP.NET.

    Créer un site web

  2. Dans la fenêtre Nouvelle application web ASP.NET - MoveShapeDemo , laissez Vide sélectionné et sélectionnez OK.

  3. Dans Explorateur de solutions, cliquez avec le bouton droit sur le projet et sélectionnez Ajouter un>nouvel élément.

  4. Dans Ajouter un nouvel élément - MoveShapeDemo, sélectionnez Installé>Visual C#>Web>SignalR, puis classe Hub SignalR (v2).

  5. Nommez la classe MoveShapeHub et ajoutez-la au projet.

    Cette étape crée le fichier de classe MoveShapeHub.cs . Simultanément, il ajoute au projet un ensemble de fichiers de script et de références d’assembly qui prennent en charge SignalR.

  6. Cliquez sur Outils>Gestionnaire de package NuGet>Console du Gestionnaire de package.

  7. Dans la console du Gestionnaire de package, exécutez la commande suivante :

    Install-Package jQuery.UI.Combined
    

    La commande installe la bibliothèque d’interface utilisateur jQuery. Vous l’utilisez pour animer la forme.

  8. Dans Explorateur de solutions, développez le nœud Scripts.

    Références à la bibliothèque de scripts

    Les bibliothèques de scripts pour jQuery, jQueryUI et SignalR sont visibles dans le projet.

Créer l’application de base

Dans cette section, vous allez créer une application de navigateur. L’application envoie l’emplacement de la forme au serveur lors de chaque événement de déplacement de souris. Le serveur diffuse ces informations à tous les autres clients connectés en temps réel. Vous en apprendrez plus sur cette application dans les sections ultérieures.

  1. Ouvrez le fichier MoveShapeHub.cs .

  2. Remplacez le code dans le fichier MoveShapeHub.cs par ce 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. Enregistrez le fichier .

La MoveShapeHub classe est une implémentation d’un hub SignalR. Comme dans le didacticiel Prise en main avec SignalR, le hub a une méthode que les clients appellent directement. Dans ce cas, le client envoie un objet avec les nouvelles coordonnées X et Y de la forme au serveur. Ces coordonnées sont diffusées à tous les autres clients connectés. SignalR sérialise automatiquement cet objet à l’aide de JSON.

L’application envoie l’objet ShapeModel au client. Il a des membres pour stocker la position de la forme. La version de l’objet sur le serveur a également un membre pour suivre les données du client qui sont stockées. Cet objet empêche le serveur d’envoyer les données d’un client à lui-même. Ce membre utilise l’attribut JsonIgnore pour empêcher l’application de sérialiser les données et de les renvoyer au client.

Mapper au hub au démarrage de l’application

Ensuite, vous configurez le mappage au hub au démarrage de l’application. Dans SignalR 2, l’ajout d’une classe de démarrage OWIN crée le mappage.

  1. Dans Explorateur de solutions, cliquez avec le bouton droit sur le projet et sélectionnez Ajouter un>nouvel élément.

  2. Dans Ajouter un nouvel élément - MoveShapeDemo, sélectionnezVisual C#>Webinstallé>, puis sélectionnez Classe de démarrage OWIN.

  3. Nommez la classe Startup et sélectionnez OK.

  4. Remplacez le code par défaut dans le fichier Startup.cs par ce 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();
            }
        }
    }
    

La classe de démarrage OWIN appelle MapSignalR lorsque l’application exécute la Configuration méthode . L’application ajoute la classe au processus de démarrage d’OWIN à l’aide de l’attribut OwinStartup assembly.

Ajouter le client

Ajoutez la page HTML pour le client.

  1. Dans Explorateur de solutions, cliquez avec le bouton droit sur le projet et sélectionnez Ajouter une>page HTML.

  2. Nommez la page Par défaut , puis sélectionnez OK.

  3. Dans Explorateur de solutions, cliquez avec le bouton droit sur Default.html et sélectionnez Définir comme page de démarrage.

  4. Remplacez le code par défaut dans le fichier Default.html par ce 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. Dans Explorateur de solutions, développez Scripts.

    Les bibliothèques de scripts pour jQuery et SignalR sont visibles dans le projet.

    Important

    Le gestionnaire de package installe une version ultérieure des scripts SignalR.

  6. Mettez à jour les références de script dans le bloc de code pour qu’elles correspondent aux versions des fichiers de script dans le projet.

Ce code HTML et JavaScript crée un rouge div appelé shape. Il active le comportement de glissement de la forme à l’aide de la bibliothèque jQuery et utilise l’événement drag pour envoyer la position de la forme au serveur.

Exécuter l’application

Vous pouvez exécuter l’application pour qu’elle fonctionne. Lorsque vous faites glisser la forme autour d’une fenêtre de navigateur, la forme se déplace également dans les autres navigateurs.

  1. Dans la barre d’outils, activez Débogage de script , puis sélectionnez le bouton de lecture pour exécuter l’application en mode Débogage.

    Capture d’écran de l’utilisateur activant le mode débogage et sélectionnant Lecture.

    Une fenêtre de navigateur s’ouvre avec la forme rouge dans le coin supérieur droit.

  2. Copiez l’URL de la page.

  3. Ouvrez un autre navigateur et collez l’URL dans la barre d’adresses.

  4. Faites glisser la forme dans l’une des fenêtres du navigateur. La forme dans l’autre fenêtre de navigateur suit.

Bien que l’application fonctionne à l’aide de cette méthode, il ne s’agit pas d’un modèle de programmation recommandé. Il n’existe aucune limite supérieure au nombre de messages envoyés. Par conséquent, les clients et le serveur sont submergés par les messages et les performances se dégradent. En outre, l’application affiche une animation disjointe sur le client. Cette animation saccadée se produit parce que la forme se déplace instantanément par chaque méthode. Il est préférable que la forme se déplace en douceur à chaque nouvel emplacement. Ensuite, vous allez apprendre à résoudre ces problèmes.

Ajouter la boucle cliente

L’envoi de l’emplacement de la forme sur chaque événement de déplacement de la souris crée une quantité inutile de trafic réseau. L’application doit limiter les messages du client.

Utilisez la fonction javascript setInterval pour configurer une boucle qui envoie de nouvelles informations de position au serveur à un débit fixe. Cette boucle est une représentation de base d’une « boucle de jeu ». Il s’agit d’une fonction appelée à plusieurs reprises qui pilote toutes les fonctionnalités d’un jeu.

  1. Remplacez le code client dans le fichier Default.html par ce 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>
    

    Important

    Vous devez remplacer à nouveau les références de script. Ils doivent correspondre aux versions des scripts dans le projet.

    Ce nouveau code ajoute la updateServerModel fonction . Il est appelé sur une fréquence fixe. La fonction envoie les données de position au serveur chaque fois que l’indicateur moved indique qu’il existe de nouvelles données de position à envoyer.

  2. Sélectionnez le bouton de lecture pour démarrer l’application

  3. Copiez l’URL de la page.

  4. Ouvrez un autre navigateur et collez l’URL dans la barre d’adresses.

  5. Faites glisser la forme dans l’une des fenêtres du navigateur. La forme dans l’autre fenêtre de navigateur suit.

Étant donné que l’application limite le nombre de messages envoyés au serveur, l’animation n’apparaît pas comme fluide au premier abord.

Ajouter la boucle du serveur

Dans l’application actuelle, les messages envoyés du serveur au client sont envoyés aussi souvent qu’ils sont reçus. Ce trafic réseau présente un problème similaire à celui que nous voyons sur le client.

L’application peut envoyer des messages plus souvent que nécessaire. La connexion peut être inondée en conséquence. Cette section explique comment mettre à jour le serveur pour ajouter un minuteur qui limite le taux de messages sortants.

  1. Remplacez le contenu de par MoveShapeHub.cs ce 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. Sélectionnez le bouton de lecture pour démarrer l’application.

  3. Copiez l’URL de la page.

  4. Ouvrez un autre navigateur et collez l’URL dans la barre d’adresses.

  5. Faites glisser la forme dans l’une des fenêtres du navigateur.

Ce code développe le client pour ajouter la Broadcaster classe . La nouvelle classe limite les messages sortants à l’aide de la Timer classe du .NET Framework.

Il est bon d’apprendre que le hub lui-même est transitoire. Il est créé chaque fois qu’il est nécessaire. Ainsi, l’application crée le Broadcaster en tant que singleton. Il utilise l’initialisation différée pour différer la Broadcastercréation de jusqu’à ce qu’elle soit nécessaire. Cela garantit que l’application crée complètement le premier hub instance avant de démarrer le minuteur.

L’appel à la fonction des UpdateShape clients est ensuite déplacé hors de la méthode du UpdateModel hub. Il n’est plus appelé immédiatement chaque fois que l’application reçoit des messages entrants. Au lieu de cela, l’application envoie les messages aux clients à un taux de 25 appels par seconde. Le processus est géré par le _broadcastLoop minuteur à partir de la Broadcaster classe .

Enfin, au lieu d’appeler directement la méthode cliente à partir du hub, la Broadcaster classe doit obtenir une référence au hub en cours d’exploitation _hubContext . Il obtient la référence avec le GlobalHost.

Ajouter une animation fluide

L’application est presque terminée, mais nous pourrions apporter une autre amélioration. L’application déplace la forme sur le client en réponse aux messages du serveur. Au lieu de définir la position de la forme sur le nouvel emplacement donné par le serveur, utilisez la fonction de animate la bibliothèque d’interface utilisateur JQuery. Il peut déplacer la forme en douceur entre sa position actuelle et sa nouvelle position.

  1. Mettez à jour la méthode du updateShape client dans le fichier Default.html pour qu’elle ressemble au code mis en surbrillance :

    <!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. Sélectionnez le bouton de lecture pour démarrer l’application.

  3. Copiez l’URL de la page.

  4. Ouvrez un autre navigateur et collez l’URL dans la barre d’adresses.

  5. Faites glisser la forme dans l’une des fenêtres du navigateur.

Le mouvement de la forme dans l’autre fenêtre semble moins saccadé. L’application interpole son mouvement au fil du temps au lieu d’être définie une seule fois par message entrant.

Ce code déplace la forme de l’ancien emplacement vers le nouvel emplacement. Le serveur donne la position de la forme au cours de l’intervalle d’animation. Dans ce cas, c’est 100 millisecondes. L’application efface toute animation précédente en cours d’exécution sur la forme avant le démarrage de la nouvelle animation.

Obtenir le code

Télécharger le projet terminé

Ressources supplémentaires

Le paradigme de communication que vous venez d’apprendre est utile pour développer des jeux en ligne et d’autres simulations, comme le jeu ShootR créé avec SignalR.

Pour plus d’informations sur SignalR, consultez les ressources suivantes :

Étapes suivantes

Dans ce tutoriel, vous allez :

  • Configuration du projet
  • Création de l’application de base
  • Mappé au hub au démarrage de l’application
  • Ajout du client
  • Exécution de l’application
  • Ajout de la boucle cliente
  • Ajout de la boucle de serveur
  • Ajout de l’animation fluide

Passez à l’article suivant pour découvrir comment créer une application web qui utilise ASP.NET SignalR 2 pour fournir des fonctionnalités de diffusion de serveur.