Live charting avec SignalR

Publié par Fabrice Michellonet sous le(s) label(s) , , , le 26 septembre 2011

SignalR is awesome ! Oui il va falloir vous habituer à entendre dire que cette librairie est un petit bijou.


tweet signalr

Mais qu'est-ce qu'elle a de si bien cette librairie SignalR ?

SignalR fournit une couche d'abstraction au-dessus des WebSocket et des long polling connections pour les développeurs .NET et fonctionne sous IIS sans avoir à installer un autre service à côté.

Jusqu'alors il existait bien des solutions commerciales de ces technos dans l'écosystème .NET mais aucune n'avait vraiment convaincu, souvent par manque d'intégration forte entre le client et le serveur; rendant la communication entre les deux fastidieuse.
Avec SignalR c'est tout le contraire, le code serveur et le code client ne semble faire qu'un. Les lignes de code glissent du serveur vers le navigateur, sans aucune lourdeur. C'est SIMPLE.

Comme d'hab, rien de mieux qu'un petit bout de code pour démontrer ça.

Bon, si vous avez lu le titre vous avez une petite idée de ce que l'on va coder...

Coté composants techniques, évidement SignalR pour la communication client/serveur et Highchart coté client pour dessiner le chart.

Après avoir créé un nouveau projet WebForm ou MVC ajoutez le package SignalR via nuget.
Intéressons-nous au code javascript. (A noter que le code lié à la configuration du chart à été omis a des fins de clarté.)

$(function () {
     var stockExchangeServer = $.connection.stockExchange;

    stockExchangeServer.drawShareValue = function (id, content) {

        if (id != this.Id) {
            return;
        }

        // set up the updating of the chart.
        var series = chart.series[0];
        var x = new Date(parseInt(content[0].Date.substr(6))).getTime(),
                y = content[0].Price;

        series.addPoint([x, y], true, true);
    };

    $.connection.hub.start(function () {
        stockExchangeServer.connect();
            .done(function (success) {
                if (success === false) {
                    console.log(":(");
                }
                console.log("connected");
            });
    });
});

Pour initier la communication avec le serveur, il suffit comme vous pouvez le voir d'utiliser la méthode $.connection.hub.start();
On se contente alors de faire appel à la méthode connect; nous implémenterons cette dernière côté serveur.... oui vous avez bien lu, côté serveur.

Remarquez également la définition de la méthode drawShareValue() qui se charge de dessiner un nouveau point dans le chart, nous ferons appel à elle dans le code serveur.


Côté serveur, nous allons définir un hub, la classe de base qui abstrait la communication client/serveur dans l'api SignalR.

public class StockExchange : Hub
    {
        private Timer _timer;

        private double _fowlerPrice = 10.2;

        private double VaryPrice()
        {
            Random rnd = new Random();
            _fowlerPrice = _fowlerPrice + (rnd.Next(-1, 2) * rnd.NextDouble());
            return _fowlerPrice;
        }

        public bool Connect()
        {
            // Set unique id for client.
            Caller.Id = Context.ClientId;

            _timer = new Timer { Interval = 1000 };

            _timer.Elapsed += (sender, e) => Send(
                new List<SharePrice>(new[]
                                         {
                                             new SharePrice
                                                 {
                                                     Date = DateTime.Now,
                                                     Price = VaryPrice(),
                                                     Share = new Share {Name = "Fowler-Corp"}
                                                 }
                                         }));
            _timer.Start();

            return true;
        }

        public void Send(IEnumerable<SharePrice> sp)
        {
            Clients.drawShareValue(Context.ClientId, sp);
        }
    }

Avez-vous remarqué la méthode Connect()? On y a fait appel à partir du code JS.
Et l'appel à drawShareValue(), fait bien référence à la méthode que l'on à définit dans le javascript. Enorme, non?

Tout cela est possible parce que SignalR utilise dans ses fondements le typage dynamic à laquelle vient s'ajouter une résolution de Propriété/Méthode "simple" par convention, évitant ainsi d'avoir à écrire du code verbeux.

Au final, voici ce que l'on peut obtenir...

chart

Bon ok, l'image ne bouge pas, il faut imaginer qu'un point vient s'ajouter chaque seconde dans le graph :)

Pour ceux qui voudrait jeter un coup d’œil à la solution entière, vous pouvez la récupérer sur Github

Avez-vous utilisé d'autres technos/framework pour faciliter les communications "temps réel" entre le serveur et le browser?