Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

Kévin Gosse

Clair, .NET, et précis

Silverlight 3 : Communication et multicast

Envoi et réception de messages

Il y a une fonctionnalité apportée par Silverlight 3 dont j'ai très peu entendu parler, à ma grande surprise : l'envoi et la réception de messages entre applications Silverlight côté client.

Sur la forme, c'est extrêmement simple. Tout gravite autour du namespace System.Windows.Messaging. Afin de ne pas interférer avec d'autres applications SL, les communications se font sur un canal nommé. La première étape pour recevoir des messages est donc de créer ce canal :

var receiver = new System.Windows.LocalMessageReceiver("channel");
receiver.MessageReceived += new EventHandler<MessageReceivedEventArgs>(Receiver_MessageReceived);
receiver.Listen();

Ce code créé un nouveau LocalMessageReceiver et l'assigne au canal "channel" (évidemment, dans la pratique, je vous suggère d'utiliser un nom fort pour éviter qu'un autre développeur n'utilise le même nom que vous). La fonction Receiver_MessageReceived est ensuite assignée à l'objet pour indiquer l'action à effectuer lors de la réception d'un message. Dans mon exemple, la fonction se contente de rediriger le contenu du message vers la console :
 
private void Receiver_MessageReceived(object sender, MessageReceivedEventArgs e)
{
        Console.WriteLine(e.Message);
}

Enfin, la méthode Listen permet d'indiquer que tout est prêt et ouvre le canal de communication. Rien de bien compliqué donc.

Pour l'envoi de messages, c'est encore plus simple. Il faut cette fois se servir de la classe LocalMessageSender. L'envoi de messages se fait de manière asynchrone.

var sender = new System.Windows.Messaging.LocalMessageSender("channel");
sender.SendAsync("Hello world !");

A noter que la classe LocalMessageSender implémente un événement SendCompleted, utile par exemple si vous voulez savoir de manière précise quand le message a été reçu.

Bien entendu, dans cet exemple, les codes d'envoi et de reception de message peuvent être placés dans des applications Silverlight différente, c'est tout l'intérêt de la chose.

 

Multicast

La première chose que j'ai tenté de faire pour tester cette nouvelle API est l'envoi de messages à plusieurs applications, en imaginant déjà une sorte de Live Mesh où les applications pourraient directement interagir entre elles. Problème : le multicast n'est pas prévu par cette API. En cas d'ouverture de deux LocalMessageReceiver sur le même canal, une exception est levée avec le message d'erreur "Error HRESULT_E_FAIL has been returned from a call to a COM component". Il faut donc s'y prendre autrement.

Le modèle qui vient tout de suite à l'esprit est un modèle client/serveur, où les clients envoient les messages au serveur, qui s'occupe de les transmettre aux autres clients. La méthode "facile" consisterait à créer une application Silverlight marquée comme serveur "en dur", mais je souhaitais une solution moins contraignante. Je me voyais donc déjà me lancer dans un système d'élection avec tous les problèmes d'accès concurrent qui en découlent, mais fort heureusement il est possible de faire plus simple.

Je ne connais pas les détails d'implémentation, mais malgré toutes mes tentatives je ne suis pas parvenu à créer deux LocalMessageReceiver simultanément sur le même canal. Il semblerait donc que le framework se charge déjà des accès concurrents, ce qui retire une belle épine du pied. A partir de là, il suffit de tenter d'ouvrir le même canal sur toutes les applications, et se baser sur l'exception levée pour déterminer si l'application sera cliente ou serveur :

bool isServer = false;
var receiver = new System.Windows.Messaging.LocalMessageReceiver("masterChannel"); 
receiver.MessageReceived += new EventHandler<MessageReceivedEventArgs>(Receiver_MessageReceived);  
try
{
       receiver.Listen();
       isServer = true;
}
catch (Exception)
{ }
bool isServer = false; 
 

Maintenant que nous avons notre serveur, il faut encore implémenter toute la logique derrière. Pour que le serveur puisse transmettre les messages, il faut qu'il conserve la liste des clients, et le nom de leur canal de communication respectif. Il faut donc assigner un nom unique à chaque application (pour cela, le générateur de GUID fera tout à fait l'affaire), et gérer un protocole permettant au client de signaler son existence :

if (!isServer)
{
      this.Id = Guid.NewGuid().ToString();
      receiver = new System.Windows.Messaging.LocalMessageReceiver(this.Id);
      receiver.MessageReceived += new EventHandler<MessageReceivedEventArgs>(Receiver_MessageReceived);
      receiver.Listen();
      var sender = new System.Windows.Messaging.LocalMessageSender("masterChannel");
      sender.SendAsync("REGISTER|" + this.Id);
}

Et le traitement des messages proprement dit :

private void Receiver_MessageReceived(object sender, MessageReceivedEventArgs e)
{
    if (e.Message.StartsWith("REGISTER|"))    
    {
        LocalMessageSender child = new LocalMessageSender(e.Message.Remove(0, 9));
        this.ChildSenders.Add(child);    
    }
    else
    {
        if (this.IsMaster)
        {
            foreach (var child in this.ChildSenders)
            {
                child.SendAsync(e.Message);
            }
        }
 
        // Traiter le message    
    }
}

C'est évidemment une implémentation sommaire. Pour une utilisation "réelle", j'ai codé une petite librairie qui permet de rendre une application Silverlight communicante. Pour cela, il suffit d'instancier la classe depuis l'application :

var communicationHandler = new MulticastChannel.CommunicationHandler(); 
communicationHandler.MessageReceived += new EventHandler<MessageReceivedEventArgs>(communicationHandler_MessageReceived); 
communicationHandler.Initialize();

Créer une méthode contenant le code à exécuter lors de la réception d'un message :

private void communicationHandler_MessageReceived(string message)
{
    Console.WriteLine(message);
}

Et enfin, envoyer à chaque fois que nécessaire un message via la méthode SendMessage :

communicationHandler.SendMessage("Hello world !");

Si vous souhaitez y jeter un oeil, j'ai mis en ligne la librairie et son code source.

En l'état, la librairie ne peut pas être utilisée dans un environnement multi-fenêtrée. En effet, il n'y a rien de prévu pour nommer un nouveau serveur si la fenêtre contenant l'ancien a été fermée par l'utilisateur. Pour gérer cela, il faudrait se baser sur l'évenement déclenché par la méthode LocalMessageSender.SendAsync, qui permet de savoir si une erreur s'est produite lors de l'envoi. A partir de là, un nouveau serveur peut être déterminé en reprenant la méthode du try/catch. Je mettrai peut être la librairie à jour prochainement à ce sujet.

Bien entendu, ce billet pourra sombrer dans les oubliettes du bidouillage si la version finale de Silverlight 3 implémente nativement le multicast pour l'envoi de messages :)

Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :
Posted: samedi 4 juillet 2009 18:07 par KooKiz
Classé sous : , ,

Commentaires

Pas de commentaires

Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- Pb lors de l’installation SharePoint 2010… par Le blog de Patrick le il y a 9 heures et 17 minutes

- [WF4] Ajouter des contraintes à une activité (2/2) par Blog de Jérémy Jeanson le il y a 14 heures et 50 minutes

- [WF4] Ajouter des contraintes à une activité (1/2) par Blog de Jérémy Jeanson le il y a 15 heures et 22 minutes

- [ASP.NET] Ne pas se faire avoir par IHttpModule et sa méthode Init() par Thomas Jaskula le il y a 23 heures et 22 minutes

- [MSTD10] SharePoint 2010 et Team Foundation Server par Philippe Sentenac [MVP SharePoint] le 03-11-2010, 10:49

- [MSTD10] SQL Server 2008 pour les développeurs et Visual Studio Team System Database Edition par Michel Perfetti [Miiitch] le 03-11-2010, 10:00

- [WF4] Localiser simplement une activité et son designer WPF par Blog de Jérémy Jeanson le 03-11-2010, 08:49

- [Techdays 2010] Webcasts et Slides par Blog Technique d'Audrey PETIT le 03-11-2010, 08:30

- NDepend v3. J’adore son intégration avec VS2010 par Thomas Jaskula le 03-11-2010, 00:18

- XNA 4.0 pour créer des jeux 3D sous Windows Phone 7 Series par Code is poetry le 03-10-2010, 14:14