mercredi 16 juin 2010

Tracer les flux d’appel à des Web service avec Ms Soap Tool Kit

Parfois quand on travaille avec les webservice on voudrait voir les XML qui sont échangé pour plusieurs raison :

- Debugging
- Certains outils (comme en .net) font ignorer complètement le coté XML des WebService et parfois celà peut amener à des bugs/problèmes incompréhensibles.
- Si on affiche les données en XSLT ça peut aider de voir la structure du XML.
- Voir les entête HTTP (surtout celles que l'on créer).

Pour celà MS a créer un super outil qui fait parti du Soap Tool Kit, Téléchargeable ici :

http://www.microsoft.com/downloads/details.aspx?familyid=c943c0dd-ceec-4088-9753-86f052ec8450&displaylang=en

Donc il faut installer ça. Puis aller dans Binaries puis lancer MSSoapT.exe

Dans ce logiciel , il faut cliquer sur File - > New Trace - > Formatted Trace

Une fenetre s'affiche



Dans local post, 8080 va très bien à moins qu'un logiciel écoute actuellement sur ce port (dans ce cas la il faut mettre autre chose).

Dans destination host il faut mettre le nom de domaine du serveur (ex : "monserveur.com").

Dans destination port , le port sur lequel écoute le serveur web du serveur (80 en général).

Puis OK.

Ensuite il faut aller changer l'endroit ou est configuré l'adresse ou sont envoyés les requêtes (par exemple web.config pour un appli asp.net).

A cet endroit il faut changer le nom de domaine du serveur avec l'adresse sur laquelle écoute mssoapt.exe (ici "localhost:8080")
Par exemple "http://monserveur.com/webservice.asmx" va devenir "http://localhost:8080/webservice.asmx".

Il faut lancer son programme client qui va faire un appel webservice, mssoapt.exe va simplement recevoir le message, le montrer, l'envoyer au serveur, recevoir la réponse, la montrer et la renvoyer au client, tout comme un proxy. Et ça donne ce genre de chose :



Pour récupérer le xml non formaté, il faut faire click droit sur un des cadre et clicker sur "Afficher la source" (les deux caddre sont des cadre Internet Explorer).

Attention à ne pas oublier de remettre l'adresse du serveur correctement. Et il ne faut pas utiliser cette technique en production :
- Il n'y a aucun moyen d'appliquer des filtre donc si il y a du traffic ça peut faire beacoup
- Le logiciel ne marche pas en multi thread je pense donc ça peut créer un goulot d'étranglement.

Utiliser un extended object pour obtenir des node xml

Dans mon travail nous affichons quasiment toutes nos données via xsl.

Parfois au milieu d'un XSL on a besoin de certaine donnée qui n'existe pas dans un fichier XML mais qui sont le résultats de l'appel d'une fonction.

1/ Créer votre objet qui possède une méthode qui appelle vos webservice

[sourcecode language="csharp"]
public class MaClasseCliente{
public XmlNode MaFonctionQuiFaitQQCH(string unParametre){
MonObjetResultat obj = MaClasse.MaMethode(unParametre);
XmlSerializer ser = new XmlSerializer(obj.GetType());
System.Text.StringBuilder sb = new System.Text.StringBuilder();
System.IO.StringWriter writer = new System.IO.StringWriter(sb);
ser.Serialize(writer, obj);
XmlDocument doc = new XmlDocument();
doc.LoadXml(sb.ToString());
return doc.LastChild;
}
}
[/sourcecode]

Ici donc je sérialize l'objet (qui est doit etre Serializable) dans un StringBuilder.
Je mets tout ça dans un XmlDocument, puis je retourne le LastChild du Document (le document a 2 enfants : la déclaration xml, et l'élément racine, donc LastChild me permet de récupérer facilement les données).

2/ On envoi l'objet au xml
Ma balise dans mon .aspx

[sourcecode language="html"]
<asp:Xml runat="server" TransformSource="style.xslt" DocumentSource="data.xml"/>
[/sourcecode]

Dans mon code behind (.aspx.cs)

[sourcecode language="csharp"]
XsltArgumentList arguments = new XsltArgumentList();
arguments.AddExtensionObject("MonObjet",new MaClasseCliente());
xml.TransformArgumentList = arguments;[/sourcecode]

3/Mon xslt maintenant
La balise xsl:stylesheet (en haut de la fiche de style)

[sourcecode language="html"]
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ms="urn:schemas-microsoft-com:xslt" xmlns:monObjetXslt="MonObjet">
[/sourcecode]

Le "xmlns:ms" c'est fait pour pouvoir utiliser une fonction spécifique au moteur XPath de ms
Et maintenant l'appel magique :)

[sourcecode language="html"]
<xsl:variable name="monObjet" value="ms:node-set(monObjetXslt:MaFonctionQuiFaitQQCH(//UneBaliseQueJeVeutEnParametre))"/>
<xsl:value-of select="$monObjet/Root/UneBalise"/>
[/sourcecode]

"ms:node-set" est comme un eval d'un objet en tant que données xml.

A faire attention :
-On ne peut avoir en paramètre que certain type de donnée : chaine, booleen, nombre, node ou liste de node
-Il faut un nombre fixe de paramètres (oubliez les "params" pour pouvoir faire de la reflection et appeler tout vos objets)
-Attention au namespaces lors de la sérialisation .La seule solution que j'ai trouvé a été de faire des Replace sur le InnerXml du XmlDocument.
-Attention , comme dans tout dev, a faire des appel en N+1 au méthode qui utilise des I/O (ex : requête SQL dans une boucle = mal). Vaut mieux tout requêter au début en une seule fois, les I/O sont très gourmand en ressource et temps d'attente.

Référence :
- addextensionobject