Le Web temps réel en ASP.NET avec « SignalR »

| Zied BEN TAHAR (Soat) | Soat |

On est parfois confronté à des situations où, dans une application Web, le serveur doit envoyer en temps réel des données à ses clients connectés. Par exemple : un service de notification, un tableau de bord ou même un service de chat.

Avant les Websockets HTML5, plusieurs techniques JavaScript pouvaient être utilisées du côté client pour simuler l'effet push/temps réel du serveur : le client envoie continuellement des requêtes au serveur pour voir s'il a de nouveaux messages qui lui sont destinés (utilisation du XMLHttpRequest et de fonctions JavaScript tels que setInterval ou setTimeout). On se retrouvait souvent à maintenir un certain nombre de lignes de code écrites en JavaScript.

Les Websockets offrent une réponse au polling client en assurant un canal bidirectionnel et full-duplex entre le client et le serveur.

N'hésitez pas à donner vos avis sur ce tutoriel sur le forum : Commentez

- Titre : Le Web temps réel en ASP.NET avec « SignalR »

- Auteurs : Zied BEN TAHAR (Soat), Soat

- Parution : 30 janvier 2013

- Mise à jour : 21 octobre 2014

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2014 Zied BEN TAHAR. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Pourquoi « SignalR » ?

- II. Création d'un Hub

- III. Vue administrateur

- IV. Vue utilisateur

- V. Définition de la route pour le Hub

- VI. Pour aller plus loin

- VII. Remerciements

I - Pourquoi « SignalR » ?

« SignalR » est une bibliothèque client/serveur intégrée fournissant toute la plomberie nécessaire pour ajouter des fonctionnalités temps-réel à une application Web ASP.NET.

Cette bibliothèque se base sur les Websockets. Quand ces derniers ne sont pas gérés par le navigateur du client, la librairie offre une solution de fallback en utilisant d'autres techniques sans avoir à changer le code de l'application côté client et serveur. « SignalR » va, en effet, masquer toute la complexité liée à la gestion des appels JavaScript au serveur. Elle va également permettre l'appel de fonctions JavaScript clients à partir du serveur.

Découvrons quelques fonctionnalités de « SignalR » avec un scénario tout simple : notifier les clients connectés sur le site en temps réel à partir d'une interface d'administration.

On va tout d'abord commencer par créer un nouveau projet « ASP.NET MVC4 » vide et après récupérer « SignalR » via « Nuget ».

En utilisant la console du gestionnaire d'extension, « Nuget » lance la commande :

Install-package Microsoft.AspNet.SignalR -pre

Cette dernière va faire le nécessaire pour récupérer toutes les dépendances dont on aura besoin pour pouvoir utiliser « SignalR » dans le projet.

Notez l'utilisation du paramètre « -pre ». « SignalR » est, à la date d'écriture de cet article, en version « release candidate ».

II - Création d'un Hub

Un Hub est une classe de l'API « SignalR » côté serveur. Elle va se charger de gérer des appels clients vers le serveur et inversement. Dans notre exemple, nous allons créer un Hub où nous définissons la méthode que l'administrateur doit appeler pour notifier tous les clients connectés sur le site.

Regardons de plus près la classe Notifier :

1. public class Notifier : Hub

2. {

3. public void NotifyAllUsers(Notification message)

4. {

5. Clients.All.Broadcast(message);

6. }

7. }

Rien de bien compliqué. Cette classe hérite de Hub et définit une méthode publique NotifyAllUsers. En définissant cette méthode, nous indiquons à « SignalR » que cette méthode pourra être invoquée par le client. La propriété Clients est héritée de Hub. Elle encapsule des informations concernant les connexions « SignalR ». All, comme son nom l'indique, représente toutes connexions clientes. La méthode Broadcast va invoquer à partir du serveur la fonction du même nom côté client avec le paramètre message.

Pour cet exemple, une notification est une classe très simple :

1. public class Notification

2. {

3. // le type de la notification

4. public NotificationType Type { get; set; }

5. // en millisecondes, durée pendant laquelle la notification est affichée

6. public int Duration { get; set; }

7. // le texte de la notification

8. public string Text { get; set; }

9. }

10. public enum  NotificationType

11. {

12. Alert = 0,

13. Notice = 1,

14. Greeting = 2,

15. HotNews = 3

16. }

Tout aspect lié à la sérialisation/désérialisation de l'objet représentant le message est géré par « SignalR ».

Notez que la property All de Clients est de type dynamic :

En définissant ce Hub côté serveur, « SignalR » va se charger, lors du démarrage de l'application, de générer un proxy en JavaScript contenant toute la mécanique nécessaire pour assurer l'interaction client/serveur avec ce Hub.

Définissons maintenant les vues administrateur et utilisateur.

III - Vue administrateur

Afin de simplifier l'exemple, tous les aspects liés à la création du contrôleur et à l'authentification de l'administrateur n'ont pas été traités dans cet article.

Commençons par créer une vue pour la page d'administration :

Dans la vue administrateur, nous allons définir les éléments nécessaires nous permettant d'invoquer la méthode NotifyAllUsers du Notifier Hub.

Tout passe par JavaScript ! Rien de bien compliqué, il suffit de référencer ces scripts dans la vue :

1. <script type="text/javascript" src="~/scripts/jquery-1.6.4.min.js"></script>

2. <script type="text/javascript" src="~/scripts/jquery.signalR-1.0.0-rc2.min.js"></script>

3. <script type="text/javascript" src="~/signalr/hubs"></script>

Notez l'importation de ce script ~/signalr/hubs. À aucun moment on ne l'a défini ou ajouté dans le projet. Ce script contient, en effet, tous les proxys JavaScript des Hubs créés côté serveur. Comme mentionné plus tôt dans l'article, « SignalR » va se charger de la création des proxys et de ce script pour nous.

Et enfin, Voici le script qui va nous permettre d'appeler la méthode NotifyAllUsers du Hub :

1. <script type="text/javascript">

2. $(function () {

3. // proxy correspondant au Hub Notifier défini côté serveur

4. var notifier = $.connection.notifier

5. // /!\ Important: Démarrer toutes les connexions aux Hubs

6. // définis côté serveur

7. $.connection.hub.start().done(function () {

8. $('#send').click(function () {

9. // Construction de la notification en Json

10. var notification =

11. {

12. Text: "Hello world",

13. Duration: 5000,

14. Type: 2

15. };

16. // invocation de la méthode NotifiyAllUsers

17. // définie dans le Hub Notifier

18. notifier.server.notifyAllUsers(notification);

19. });

20. });

21. });

22. </script>

$.connection.notifier fait référence au Hub créé côté serveur. En effet, si vous regardez le contenu de /signalr/hub, vous allez trouver un JavaScript. Ce script a été généré dynamiquement par « SignalR » à partir du ou des Hubs créés côté serveur.

Le format « Json » est utilisé pour définir une notification.

IV - Vue utilisateur

Pour afficher les notifications destinées à tous les utilisateurs du site, il est plus logique de voir apparaître les notifications sur toutes les pages. Je vous recommande d'écrire le JavaScript destiné aux pages utilisateurs dans le « Layout » (si vous utilisez Razor comme view engine) des vues utilisateur (Master page si vous avez opté pour le view engine classique aspx).

Revoyons ce que nous avons défini dans notre Hub.

1. Clients.All.Broadcast(message);

Afin de publier le message à tous les clients connectés, nous devons déclarer côté client JavaScript la méthode que le serveur va invoquer :

1. <script src="~/scripts/jquery-1.6.4.min.js"></script>

2. <script src="~/scripts/jquery.signalR-1.0.0-rc2.min.js"></script>

3. <script src="~/signalr/hubs"></script>

4. <script>

5. $(function () {

6. // proxy correspondant au Hub Notifier défini côté serveur

7. var notifier = $.connection.notifier;

8. // Déclaration de la fonction que le serveur pourra invoquer

9. notifier.client.broadcast = function (message) {

10. $("#text").html(message.Text); // mettre à jour le contenu du bloc destiné à afficher le message

11. $('#notification').show(1000) // afficher la notification

12. .delay(message.Duration) // durée spécifiée dans le message envoyé

13. .hide(1000); // cacher le message après 'message.Duration' millisecondes

14. };

15. // Important : démarrer toutes les connexions aux Hubs

16. // déclarés côté serveur

17. $.connection.hub.start();

18. });

19. </script>

20. <div id="notification" class="notificationStyle">

21. <div id="text"></div>

22. </div>

23. <style>

24. .notificationStyle

25. {

26. background:#e9e9e9;

27. width:250px;

28. border-style:solid;

29. border-width:2px;

30. border-color:#e1e1e1;

31. height:100px;

32. overflow:hidden;

33. box-shadow: 0px 0px 10px 0px #656565;

34. display:none;

35. }

36. </style>

V - Définition de la route pour le Hub

Une route doit être définie pour le ou les Hubs créés. Il nous faudra la définir dans la méthode Application_Start du Global.asax. Cela va permettre d'enregistrer la route ~/signalr.

1. protected void Application_Start()

2. {

3. AreaRegistration.RegisterAllAreas();

4. // Définition de la route par défaut

5. RouteTable.Routes.MapHubs();

6. WebApiConfig.Register(GlobalConfiguration.Configuration);

7. FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);

8. RouteConfig.RegisterRoutes(RouteTable.Routes);

9. BundleConfig.RegisterBundles(BundleTable.Bundles);

10. }

Vous pouvez, bien entendu, choisir un autre nom pour la route. Il ne faudra pas dans ce cas oublier de renommer les références vers le script /signalr/hub avec le nom que vous aurez choisi.

VI - Pour aller plus loin

Comme vous avez pu le constater, mettre en place une application « ASP.NET MVC » avec des fonctionnalités push “temps réel” est facile avec « SignalR ». Les codes côté client et serveur se retrouvent réduits.

« SignalR » offre d'autres fonctionnalités intéressantes, que je n'ai pas abordées dans cet article, telles que : la prise en charge de groupes de clients, la détection des connexions et déconnexions des clients et la gestion des autorisations.

J'invite les plus curieux d'entre vous à regarder de plus près cette API !

Vous trouverez ici le code de cet article.

VII - Remerciements

L'équipe de la rédaction .NET remercie sincèrement Soat de nous avoir autorisés à publier cet article sur Developpez.com. Soat est une société de conseil spécialisée dans l'accompagnement de ses clients, tout au long du cycle de vie de leurs projets et le développement de technologies Java et Web.

Nous remercions également Vincent VIALE pour la mise au gabarit et Malick SECK pour sa relecture orthographique.

N'hésitez pas à donner vos avis sur ce tutoriel sur le forum : Commentez