Utilisation de xsd.exe pour le traitement complexe de message XML à l’aide de .Net

Florian CAILLAUD
Publié par Florian CAILLAUD
Catégorie : BizTalk
18/07/2017

CONTEXTE

 

Dans un projet Biztalk, il existe plusieurs moyens de modifier ou transformer des messages XML. Ceux-ci peuvent dépendre de l’élément dans lequel le traitement est réalisé (orchestration, map ou pipeline). Il est possible d’opérer les modifications grâce à :

  • des requêtes XPath (ou la fonction xpath dans le cas d’une orchestration)
  • l’affectation de nouvelles valeurs aux propriétés distinguées ou promues (dans le cas d’une orchestration)
  • une succession de fonctoïds (dans le cas d’une map)
  • l’appel de méthodes d’une bibliothèque externe

Nous avons fait le choix de traiter la modification de messages XML dans une orchestration à l’aide de méthodes (que l’on appellera helpers) d’une bibliothèque externe. L’approche proposée est cependant utilisable au sein d’un pipeline ou d’une map.
Cet article est organisé autour des deux axes suivants :

  • comment manipuler un message XML sous forme d’objet C# ?
  • pour quelles raisons et dans quelles conditions cette approche est intéressante malgré certaines limitations ?

 

MISE EN PLACE

 

Afin d’inscrire cette approche dans un exemple concret, nous proposons la mise en place d’une application Biztalk simple. Pour cela, nous créons un projet Biztalk nommé BlogProject_XSDTool au sein d’une solution BlogProject.

 

Dans ce projet, nous construisons un schéma ProductList contenant des éléments Product (nœud répétable).

 

Nous ajoutons également une orchestration composée d’un port logique de réception (pour des messages ProductList), un bloc Assignment (qui ne fait qu’affecter le message d’entrée au message de sortie) et un port logique d’envoi (pour des messages ProductList)

 

 

Ce projet est déployé au sein d’une application Biztalk dans laquelle les ports d’entrée et de sortie de l’orchestration sont respectivement liés à un emplacement de réception (via un port de réception) et à un port d’envoi, tous deux de type FILE.
Cette construction permet donc de déposer un fichier XML de type ProductList dans un répertoire et de récupérer le message en sortie sous la forme d’un fichier de type ProductList dans un autre répertoire.
Pour finir, nous créons un projet Bibliothèque de classes BlogProject_Helpers dans la solution BlogProject et l’ajoutons comme référence du projet Biztalk. C’est dans ce projet que nous allons mettre en place la modification des messages XML.

 

GÉNÉRATION D’UNE CLASSE C# GRÂCE À XSD.EXE

 

Le but est de transformer un message XML en objet C# pour pouvoir le manipuler à l’aide du Framework .Net. Pour cela, nous allons utiliser l’ outil XML Schema Definition (xsd.exe) qui est fourni avec Visual Studio et est apparu avec la version 2.0 du Framework .Net.
Cet utilitaire permet de générer des schémas XML ou des classe C# à partir de fichiers XDR, XML et XSD ou de classes C# (comme nous le montre la documentation). La fonctionnalité qui nous intéresse ici est la génération d’une classe C# à partir d’un schéma XML (.xsd).
Pour réaliser cette opération, il faut ouvrir le Developer Command Prompt de Visual Studio est taper la commande suivante :

xsd.exe {chemin_vers_le_schéma}\ProductList.xsd /c /o:{chemin_vers_le_dossier_de_la_classe}

Il faut spécifier le chemin vers notre fichier XSD à la place de {chemin_vers_le_schema} et le chemin vers le dossier dans lequel nous voulons déposer la classe générée à la place de {chemin_vers_le_dossier_de_la_classe} (dans notre cas, dans le dossier du projet BlogProject_Helpers).
Une fois la commande exécutée, un fichier ProductList.cs apparait dans le dossier choisi. Voici un aperçu :

UTILISATION DE LA CLASSE GÉNÉRÉE

 

Pour utiliser la classe nouvellement générée, nous créons une classe ProductListBuilder. Cette classe va nous permettre, dans un premier temps, de construire une instance C# de ProductList à partir d’un XLANGMessage (documentation) venant de notre orchestration et, après modification éventuelle, de convertir cette instance en XLANGMessage pour l’orchestration.


 

Le type CustomBTXMessage, à ajouter dans le projet BlogProject_Helpers, permet de réaliser la conversion entre l’instance d’un objet sérialisable et un XLANGMessage, grâce à son héritage de BTXMessage (documentation).



 

Après compilation, il est possible de réaliser cet appel dans le bloc Assignment de l’orchestration :


 

Evidemment, pour le moment, cela ne fait rien de plus que la simple affectation de la partie Mise en place. Mais nous pouvons déjà voir les avantages et les inconvénients de cette approche.

 

Limitations :

 

  • Développement : Il existe indéniablement un surcoût de développement par rapport à une simple map (que l’on peut réaliser en 10 secondes !)
  • Maintenabilité : Si le schéma utilisé change, il faut à nouveau générer la classe pour être sûr que chaque éléments et attributs soient à jour (dans le cas d’une map, il est possible que la mise à jour soit automatique).
  • Temps d’exécution : La désérialisation de l’instance peut être coûteuse pour des grands messages.

 

Avantages :

 

  • Développement : Cela permet d’utiliser toutes les fonctionnalités du Framework .Net pour réaliser efficacement des traitements complexes (voir partie suivante), là où une map montrerait ses limites même avec l’utilisation d’un script XSL.
  • Maintenabilité : Le code peut être testé dans un test unitaire sans déploiement pour valider les évolutions des schémas concernés.
  • Portabilité : Cette opération peut être réalisée dans une orchestration (comme notre exemple), mais également dans un composant de pipeline ou une map (via le fonctoïd script).

 

UTILITÉ DE L’APPROCHE À TRAVERS UN EXEMPLE

 

Ce qui ressort des parties précédentes est que l’approche présentée n’a pas vraiment d’intérêt pour des transformations ciblées ou simples que l’on pourra réaliser plus facilement avec XPath ou une map, par exemple. Cependant, certaines transformations complexes justifient parfaitement l’utilité d’un helper.
L’exemple que nous avons choisi de mettre en œuvre est le suivant. Un produit possède un identifiant, un nom, une couleur et une quantité. Nous voulons cumuler les quantités, et donc fusionner les éléments Product, mais seulement quand l’identifiant, le nom et la couleur sont les mêmes. Dans le cas contraire, il faut bien garder deux éléments distincts.
Grâce à la modélisation de notre message sous forme d’objet C#, il est possible d’utiliser des outils comme LINQ To XML. Le problème se résout alors en modifiant la classe ProductListBuilder de la manière suivante :

 

La requête LINQ (en vert) transforme d’abord chaque produit en une instance de type anonyme {Id, Name, Quantity, Color} pour le manipuler plus facilement. Ensuite elle groupe ces instances grâce à la clé {Id, Name, Color}, en spécifiant qu’il faut cumuler les quantités des éléments fusionnés.
Une liste de ProductListProduct est alors construite avec linqProducts et affectée à la propriété Product de l’instance de type ProductList à renvoyer.
Cette méthode est appelée dans NewProductList() à la place de ConstructProductList(). Il n’est donc pas nécessaire de modifier l’orchestration (encore un avantage !).
Si l’on déploie le projet Biztalk et ses dépendances dans l’application Biztalk, le fichier entrant (à gauche) est bien transformé, comme souhaité, en sortie (à droite).



CONCLUSION

 

L’approche décrite dans cet article ne s’applique idéalement qu’à certaines situations car en raison des surcoûts engendrés (développement et temps d’exécution), s’il est possible de faire sans, il vaut mieux éviter. Mais si des traitements complexes (comme dans notre exemple) sont nécessaires, c’est une solution propre et relativement directe qui permet de résoudre le problème aussi bien dans une orchestration, dans une map ou dans un pipeline.