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

- TechDays Paris 2010 : La BI dans SharePoint 2010 par Blog Technique de Romelard Fabrice le il y a 1 heure et 9 minutes

- TechDays Paris 2010 : Déploiement de nouvelles technologies – Retour d’expérience par l’informatique de Microsoft par Blog Technique de Romelard Fabrice le il y a 2 heures et 36 minutes

- TechDays Paris 2010 : Plan de migration vers SharePoint 2010 par Blog Technique de Romelard Fabrice le il y a 6 heures et 19 minutes

- TechDays Paris 2010 : La pleinière du second jour par Blog Technique de Romelard Fabrice le il y a 7 heures et 24 minutes

- Visual Studio 2010 and .NET Framework 4 Release Candidate now available par Matthieu MEZIL le il y a 10 heures et 30 minutes

- Création d’une base de donnée sous SQL Azure par Le Blog (Vert) d'Arnaud JUND le il y a 11 heures et 26 minutes

- TechDays Paris 2010 : Les Services d’applications dans SharePoint 2010 par Blog Technique de Romelard Fabrice le il y a 21 heures et 25 minutes

- TechDays Paris 2010 : La GED et SharePoint 2010 par Blog Technique de Romelard Fabrice le 02-08-2010, 16:54

- TechDays Paris 2010 : SharePoint 2010 et Les réseaux sociaux par Blog Technique de Romelard Fabrice le 02-08-2010, 15:40

- TechDays Paris 2010 : SharePoint 2010 – Description et nouveautés par Blog Technique de Romelard Fabrice le 02-08-2010, 14:33