Blog de JP Gouigoux

30/05/2008

Je suis (enfin) MCSD.NET !

Filed under: .NET,Perso — jpgouigoux @ 7:28
Tags:

Ca y est : quatre ans après avoir passé la première certification .NET de Microsoft, j’ai enfin réussi à finir le premier cycle de certifications pour être Microsoft Certified Solution Developer. A cette époque là, c’était le top du top… Malheureusement (enfin, pour être honnête, c’est normal), Microsoft a depuis rajouté des niveaux à ses certifications. Il va falloir passer encore deux (ou trois ?) examens passerelles pour me mettre à jour sur le nouveau programme et devenir MCPD.

J’espère vraiment que ça ne changera pas trop vite après, histoire de ne pas passer ma vie à courir après des examens. Encore, tant que c’est des examens comme WinForms ou ASP.NET ou la sécurité, ça va : le sujet est intéressant, et surtout, si on connaît bien le code, on n’est pas pris au piège par les questions. Mais le 70-300, qui est celui sur l’architecture, est vraiment très différent : ce sont des exercices de mise en situation réelle, avec des questions sur les choix d’architecture conceptuelle ou technique. Les réponses sont parfois un peu bizarres, et il y a quelques cas où, vraiment, tout ce qui et proposé paraît ne pas coller à la question. Ca ne vient pas de l’anglais (oui, c’est un des rares examens à ne pas être disponible en français), je suis à peu près bilingue. Les questions sont parfois très vagues, et en architecture informatique, chacun fait son choix. Ce n’est pas comme du code où c’est bon ou mauvais.

La prochaine certification sera le MCTS 70-341 sur SQLServer 2005. Ensuite, les examens passerelles, et peut-être que je pousserai le vice jusqu’à passer les examens WPF et WCF, qui ont été rajoutés récemment. Personnellement, je ne peux que recommander ce cycle de certification. Je ne sais pas ce que valent celles sur les systèmes, SQLServer ou même les certifications non-Microsoft, mais je peux dire que celles que j’ai passées m’ont fait apprendre pas mal de choses en lisant les bouquins de préparation et en faisant les exercices proposés. Il y a bien sûr beaucoup de choses à apprendre, et on se retrouve à bachoter pour certaines classes qu’on n’utilise presque jamais, mais qu’on est obligés d’apprendre pour parer à toute éventualité, mais dans l’ensemble, ce sont des techniques qu’on peut vraiment appliquer au travail.

25/05/2008

Retrouver une valeur d’énumération depuis son libellé par réflexion

Filed under: .NET — jpgouigoux @ 8:14
Tags:
public enum ModeTraitement : byte { COMPLET = 0, MIXTE = 1, REDUIT = 2 };
<ActionPreventive ModeTraitement="COMPLET">

Imaginez que vous devez mettre en place une désérialisation à la main depuis un fichier XML, parce que la classe ne correspond pas à ce dont vous disposez. Il est plus simple de parcourir ledit fichier et, pour chaque élément, créer par réflexion l’instance de classe correspondante, puis faire de même pour les attributs. Dans le cas de type simple, pas de problème.

Mais souvent, quand les fichiers XML doivent être facilement lisible, vous ne disposez pas pour un attribut correspondant à un type énuméré de sa valeur entière, mais plutôt du libellé associé.

Par exemple :

Bref, pas de chance, car vous ne pouvez pas affecter directement la valeur par réflexion sur la propriété avec le genre de code ci-dessous :

PropertyInfo Propriete = TypeActivite.GetProperty(Attribute.LocalName);
Propriete.SetValue(ActionPreventive, "COMPLET", null);

Vous aurez une erreur car le type doit être byte, et non pas string tel que vous tentez de le faire.

La solution : parcourir par réflexion les valeurs possibles de l’énumération. Le principe paraît simple, mais je fais quand même un petit billet là-dessus, parce que j’ai mis un peu de temps à trouver.

PropertyInfo Propriete = TypeActionPreventive.GetProperty("ModeTraitement");
if (Propriete.PropertyType.IsEnum)
{
 foreach (FieldInfo AtomeEnum in Propriete.PropertyType.GetFields(BindingFlags.Public | BindingFlags.Static))
 if (AtomeEnum.Name.Equals("COMPLET"))
 {
  Propriete.SetValue(ActionPreventive, (byte)AtomeEnum.GetValue(null), null);
  break;
 }
}

En espérant que ça serve à quelqu’un.

05/05/2008

XSL/FO et .NET

Filed under: .NET,FOP — jpgouigoux @ 9:30
Tags: , , ,

Vous êtes-vous déjà demandé comment faire pour générer un PDF en XSL-FO depuis ASP.NET, ou pour le coup n’importe quelle application .NET ? J’ai eu beau chercher, je n’ai pas trouvé de moteur XSL-FO écrit en code managé et open-source.

La solution glanée sur différents sites web est de faire de l’interop avec ApacheFOP, qui est écrit en Java. Mais là, deux voies sont possibles :

– Ou bien on recompile le code Java en J#, et on obtient des assemblages .NET nécessitant les redistribuables J# pour fonctionner. Avantage : le tout ne pèse que quelques Mo. Inconvénient : ça n’a aucune chance de fonctionner sous Mono.

– Ou bien on exécute en mémoire les JAR en passant par IKVM, qui est une machine virtuelle embarquée dans un processus .NET. Avantage : c’est propre et tout tourne en mémoire, de plus pas de problème théoriquement avec Mono, vu qu’IKVM est carrément livré avec. Inconvénient : ça pèse une trentaine de Mo, car il faut livrer avec la totalité des classes Java. Il doit y avoir moyen de faire autrement en générant une dll IKVM.ClassPath.dll avec seulement ce qui est nécessaire, mais je n’ai pas essayé.

On va expliquer sur ce post la deuxième méthode, qui de mon point de vue est la meilleure. Oui, je sais, ça a déjà été fait sur d’autres pages web, mais je n’ai rien trouvé qui était à jour avec la dernière version de FOP et avec la liste des références nécessaires.

Récupération des librairies

On commence par récupérer FOP sur le site Apache, http://xmlgraphics.apache.org/fop/download.html (la toute dernière version stable est la 0.94). On va également télécharger la dernière version en date de IKVM, à savoir la 0.36.0.11 sur http://sourceforge.net/project/showfiles.php?group_id=69637.

Petite remarque au passage : je suis toujours autant émerveillé de la modestie des équipes capables de réaliser un développement aussi remarquable, et de laisser un numéro de version inférieur à 1. Quand on voit des logiciels soi-disant professionnels toujours aussi buggés en version 10, on se dit que beaucoup d’entre eux devraient prendre exemple sur les développements OpenSource.

On décompresse ensuite tout ça dans deux répertoires /FOP et /IKVM.

Recompilation des librairies FOP par IKVM

IKVM fournit un environnement d’exécution .NET d’une VM Java sous forme d’un exécutable, mais également un compilateur permettant de générer des assemblages .NET à partir des JAR, et qui se nomme IKVMC.

Dans notre cas, on se place dans /IKVM/bin, et on lance successivement les commandes suivantes :

ikvmc -target:library
    -reference:IKVM.OpenJDK.ClassLibrary.dll
    /fop-0.94/lib/xml-apis-1.3.02.jar

ikvmc -target:library
    -reference:IKVM.OpenJDK.ClassLibrary.dll
    -reference:xml-apis-1.3.02.dll
    /fop-0.94/lib/xercesImpl-2.7.1.jar

ikvmc -target:library
    -reference:IKVM.OpenJDK.ClassLibrary.dll
    -reference:xml-apis-1.3.02.dll
    /fop-0.94/lib/avalon-framework-4.2.0.jar

ikvmc -target:library
    -reference:IKVM.OpenJDK.ClassLibrary.dll
    -reference:xml-apis-1.3.02.dll
    /fop-0.94/lib/batik-all-1.6.jar

ikvmc -target:library
    -reference:IKVM.OpenJDK.ClassLibrary.dll
    /fop-0.94/lib/commons-logging-1.0.4.jar

ikvmc -target:library
    -reference:IKVM.OpenJDK.ClassLibrary.dll
    /fop-0.94/lib/commons-io-1.3.1.jar

ikvmc -target:library
    -reference:IKVM.OpenJDK.ClassLibrary.dll
    /fop-0.94/lib/xmlgraphics-commons-1.2.jar

ikvmc -target:library
    -reference:IKVM.OpenJDK.ClassLibrary.dll
    -reference:xml-apis-1.3.02.dll
    -reference:batik-all-1.6.dll
    -reference:commons-logging-1.0.4.dll
    -reference:xmlgraphics-commons-1.2.dll
    -reference:commons-io-1.3.1.dll
    -reference:avalon-framework-4.2.0.dll
    /fop-0.94/build/fop.jar

Si vous avez besoin d’assemblages signés, il suffit de spécifier la directive -keyfile:[votre fichier .snk] ou bien -key:[le nom de votre container de clé]. IKVMC contient de nombreuses autres options qui peuvent se réveler très utiles. La prise en compte de la signature par nom fort, dans mon cas, était très importante, et ce fut un vrai soulagement de voir que le paramètre était présent. Je me voyais déjà désassembler l’IL depuis la DLL puis recompiler en ajoutant la signature, et je ne suis même pas sûr que ça soit possible…

Utilisation des assemblages créés

Une fois ceci fait, vous pouvez créer un projet .NET dans lequel vous allez simplement mettre en référence les librairies fop.dll et IKVM.ClassPath.dll générées précédemment. Placer au même endroit toutes les autres références, qui ne seront pas nécessaires pour la compilation, mais indispensables lors de l’exécution. Vous pouvez ensuite taper le genre de code suivant pour vérifier que tout fonctionne. J’ai enlevé tout ce qui est gestion des exceptions et génération des noms de fichiers pour simplifier le code et ne faire voir que ce qui a vraiment du sens pour un tutoriel sur XSL-FO.

Note : je préfère écrire systématiquement les noms de classes complets dans ce genre d’exemple. Je trouve qu’on a toujours du mal à savoir d’où viennent les classes sinon, surtout qu’il est très facile d’oublier de donner les using lorsqu’on copie une simple portion de classe. Dans la pratique, il est bien sûr plus clair d’utiliser des noms de classe simples avec des using.
public void GenererPDF(System.Xml.XmlDocument Source, string FichierXSLFO, string FichierResultatPDF)
{
    // Récupération du fichier XSL
    System.Xml.Xsl.XslCompiledTransform Moteur = new System.Xml.Xslt.XslCompiledTransform();
    Moteur.Load(FichierXSLFO);

    // Application de la transformation
    string FichierResultatFO = System.IO.Path.GetTempFileName();
    System.Xml.XmlTextWriter Scribe = new System.Xml.XmlTextWriter(FichierResultatFO, System.Text.Encoding.Default);

    Moteur.Transform(Source.CreateNavigator(), Scribe);
    Scribe.Close();

    // Création du PDF par interop IKVM avec ApacheFOP
    java.io.File fo = new java.io.File(FichierResultatFO);
    java.io.File pdf = new java.io.File(FichierPDFGenere);
    org.apache.fop.apps.FopFactory fopFactory = org.apache.fop.apps.FopFactory.newInstance();
    org.apache.fop.apps.FOUserAgent foUserAgent = fopFactory.newFOUserAgent();
    java.io.OutputStream sortie = new java.io.BufferedOutputStream(new java.io.FileOutputStream(pdf));
    org.apache.fop.apps.Fop fop = fopFactory.newFop("application/pdf", foUserAgent, sortie);
    javax.xml.transform.TransformerFactory factory = javax.xml.transform.TransformerFactory.newInstance();
    javax.xml.transform.Transformer transformer = factory.newTransformer();
    javax.xml.transform.Source src = new javax.xml.transform.stream.StreamSource(fo);
    javax.xml.transform.Result res = new javax.xml.transform.sax.SAXResult(fop.getDefaultHandler());
    transformer.transform(src, res);
    sortie.close();
}

Résultat

Une fois que les premiers résultats fonctionnels ont été atteint, la curiosité pousse à aller voir combien tout ça prend en mémoire. Il y a en effet finalement 13 librairies à mettre en place pour faire fonctionner le tout, pour un total de 36 Mo. Vu que toutes les classes de Java ont été reproduites en IKVM, c’est un peu logique, mais ce qui est intéressant, c’est que la CLR, comme pour des librairies .NET standards, ne charge que ce dont elle a besoin, à savoir en gros 5 Mo, et prend quelques dizaines de Mo pour un gros PDF, mais cette partie de mémoire est considérée comme ponctuelle, et sera libérée lors du prochain passage du garbage collector.

Bref, ça marche ! Honnêtement, je ne me suis pas penché sur IKVM pour vous indiquer clairement comment, mais je préfère avoir un produit qui fonctionne sans savoir pourquoi que l’inverse.

Créez un site Web ou un blog gratuitement sur WordPress.com.