Nicolas Torrent
MSMQ
Principe de base de l'utilisation de Message Queuing (MSMQ)
Par Nicolas Torrent publié le 02/08/2004 à 10:07, lu 43821 fois, 1 pages
Introduction
Le but de cet article est d'utiliser les fonctionnalités de base du Message Queuing (MSMQ) : le stockage de message.
MSMQ est une infrastructure de messagerie et un outil de développement pour la création d'applications de messagerie distribuées pour les systèmes d'exploitations Microsoft Windows.

On verra comment :
  1. Envoyer et recevoir des messages vers MSMQ à l'aide du Framework .Net
  2. Encapsuler nos objets dans les messages
  3. Exploiter ces messages
Exemple

Il arrive pour certaines applications que les ressources processeurs nécessaires ne soient pas suffisantes. Il faut donc mettre en place des mécanismes pour y palier.
Prenons en exemple un site Web de gestion d'images qui permet à l'utilisateur de choisir la liste des images qu'il veut acheter. Une fois ses images sélectionnées, celles-ci lui seront délivrées sous la forme d'une archive Zip.
La création des archives est un processus qui prend du temps, des ressources (documents de taille importante) surtout si plusieurs utilisateurs requêtent ce service en même temps. Cela conduit à coup sûr à l'écroulement du serveur.
Pratique
Nous allons voir un exemple concret qui traite le processus complet d'archivage de documents à travers l'envoi de demandes (messages MSMQ).

Pour cela, on utilise deux applications :
  • Le client : une application Windows qui enverra les messages (demande d'archivage de documents)
  • Le serveur : une application Windows qui se mettra en attente de nouveau messages et qui s'occupera du processus d'archivage
Schéma global :

Définition des messages
Il faut commencer par définir la structure du message à envoyer. Dans notre cas, ce message doit contenir toutes les informations nécessaires à l'archivage :
  • le nom du fichier à zipper (ou l'ensemble des fichiers)
  • le nom de l'archive à créer
  • le répertoire de destination qui contiendra l'archive
La définition du message est faite à travers une classe nommée ZipMessage. On verra dans la suite du document comment nous pouvons sérialiser et dé-sérialiser l'instance de cette classe encapsulée dans le message MSMQ.

using System;

namespace ClassLibraryMSMQMessages.Zip
{
	/// <summary>
	/// Contains the different properties to zip a file.
	/// </summary>
	/// 
	[Serializable]
	public class ZipMessage
	{
		private string _fileName, _zipName, _saveLocation;


		public ZipMessage() {

		}

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="fileName">Absolute path name of the file to zip</param>
		/// <param name="zipName">Zip name</param>
		/// <param name="saveLocationPath">Save directory path</param>
		public ZipMessage(string fileName, string zipName, string saveLocationPath)
		{
			_fileName = fileName;
			_zipName = zipName;
			_saveLocation = saveLocationPath;
		}

		/// <summary>
		/// Absolute path name of the file to zip
		/// </summary>
		public string FileName {
			get {
				return _fileName;
			}
			set {
				_fileName = value;
			}
		}

		/// <summary>
		/// Zip Name
		/// </summary>
		public string ZipName {
			get {
				return _zipName;
			}
			set {
				_zipName = value;
			}
		}

		/// <summary>
		/// Save directory path
		/// </summary>
		public string SaveLocationPath {
			get {
				return _saveLocation;
			}
			set {
				_saveLocation = value;
			}
		}
	}
}
Remarque : Cette classe doit être marquée comme sérialisable en utilisant l'attribut [Serializable] afin de signaler aux formateurs que ses instances pourront être sérialisées.
Initialisation de la file d'attente
La première chose à faire est d'initialiser la file d'attente MSMQ. Pour cela, le Framework met à notre disposition le namespace System.Messaging.

On utilise la classe MessageQueue que l'on initialise :
  • Path : Nom de file d'attente à créer. Dans notre exemple, on en créé une privé : \Private$\ZipQueue. Il existe des files d'attentes privées et publiques (voir aide de Message Queuing pour les différents cas d'utilisation)
  • Formatter : Le formateur permet de définir le type de sérialization à utiliser. Dans notre exemple, on prend un XmlMessageFormatter qui sérialize les objets en XML. Comme notre classe ZipMessage a été marquée comme sérialisable, notre objet sera automatiquement sérialisé en XML.
Remarque :

Il existe différents types de formateurs :

  • XmlMessageFormatter : Sérialise l'objet en Xml.
    • Avantage : Dans le cas où l'application tombe en panne. On a toujours la possibilité de lire le contenu des messages (car en Xml)
  • BinaryMessageFormatter : Sérialise sous forme binaire.
    • Avantage : Rapidité, Plus compact que le XML
    • Inconvénient : Impossible de lire le contenu
  • Formateur spécifique : Permet de définir son propre formalisme de sérialisation.
On peut utiliser l'outil RAD pour créer une instance de la classe MessageQueue afin de changer plus facilement ses propriétés :




La classe MessageQueue possède des méthodes statiques qui permettent de manipuler facilement les files d'attentes MSMQ (création, suppression, ...).

Dans notre exemple, lorsqu'on envoi le message pour la première fois, on créé la file d'attente :
if (!MessageQueue.Exists(messageQueueZip.Path))
	MessageQueue.Create(messageQueueZip.Path);
Envoi du message
L'instance de notre classe MessageQueue comporte une méthode Send qui permet d'envoyer notre message :

try {
	// Create message
        ZipMessage msg = new ZipMessage(textBoxSelectedPath.Text,
                                        System.IO.Path.GetFileNameWithoutExtension(textBoxSelectedPath.Text),
                                        @"c:\temp\zipFiles");

	// Send message
	messageQueueZip.Send(msg);

	// Logs
	labelLog.Text = "Msg sended";
}
catch {
	labelLog.Text = "Send message error";
}
Comme le montre le code précédent, on passe directement à la méthode Send l'instance de notre classe ZipMessage. C'est la classe XmlMessageFormater qui va s'occuper de sérialiser notre objet en XML.

Remarques :
  • On utilise le constructeur valué de notre classe ZipMessage pour initialiser directement les valeurs.
  • On peut vérifier que les messages ont bien été envoyés. Pour cela, aller dans gérer sur le poste de travail. Naviguer dans « services et applications », puis sélectionner « Message Queuing » :

Consommer les messages MSMQ
Maintenant que les messages ont été envoyés, on peut les consommer comme on le désire. Dans notre exemple, on utilise une application Windows qui :
  • attend de nouveaux messages
  • créée l'archive correspondante
Dans notre exemple, on utilise un simple Thread qui va boucler et attendre qu'un message soit déposé dans la file d'attente. Nous aurions bien sûr pu utiliser un pool de Thread pour optimiser la génération des archives.
while(true && !_stopZipThread) {
	Thread.Sleep(1000);
	try {
		ClassLibraryMSMQMessages.Zip.ZipMessage msg = (ClassLibraryMSMQMessages.Zip.ZipMessage)messageQueue1.Receive(new TimeSpan(0,0,1)).Body;
		CreateZipFromMessage(msg);
	}
	catch (MessageQueueException) {
		listBoxZipFiles.Items.Insert(0,"No message");
	}
}
Remarque : Attention, il faut trouver un compromis entre la vitesse de traitement et les ressources systèmes demandées.
Lecture du message
La lecture des messages se fait à l'aide de la classe MessageQueue qui propose deux méthodes :
  • Read : Le message est lu et enlevé de la file d'attente
  • Peek : le message est lu et laissé dans la file d'attente
Ces 2 méthodes renvoient une instance de la classe Message. On utilise la propriété Body pour récupérer notre objet encapsulé.

Remarque importante : L'appel a la propriété Body du message met automatiquement en oeuvre le processus de dé-sérialisation de notre objet à travers la classe XmlMessageFormater. On peut donc envoyer et manipuler des objets par l'intermédiaire de MSMQ de façon transparente.

Remarque : En général, les messages qui arrivent les premiers dans la file d'attente sont les premiers qui sortent. Cependant, il est possible de poster des messages avec priorités différentes qui modifieront l'ordre de récupération des messages.
Création des archives
La création des archives se fait à l'aide d'une Assemblie extérieur dont on ne décrira pas le fonctionnement. Mais vous pouvez en lire plus ici : Compresser/Décompresser des archives Zip en C# avec #ziplib par Mathieu Kempé.
Gestion des Threads
La gestion des threads est on ne peut plus simple dans cet exemple et on ne s'étendra pas dessus.
Conclusion
Pour résumer, l'utilisation de MSMQ est très simple et quasiment transparente à l'utilisation. On constate avec l'expérience que ce type d'application convient tout à fait dans les cas suivants :
  • application de type asynchrone : l'envoi de message n'est pas bloquant et permet de poursuivre le traitement
  • lorsqu'on cherche à optimiser les performances (lancement de processus différés)
  • les données qui transitent (messages) ne sont pas volatiles et sont sauvegardées (si le serveur à une panne les messages déjà présents dans la file d'attente sont sauvegardés)
  • et dans de nombreux autres cas ...
Pré-requis
Nécessite la présence :
  • Service MSMQ : Aller dans ajout / suppression de programmes – Ajouter ou supprimer des composants Windows – Cocher Message Queuing

 
» Démarrer une discussion
 
Discussion démarée par makay37 le 19/08/2009 à 15:48, 1 commentaire(s).