mardi 26 octobre 2010

utiliser Castle Monorail dans un site web asp.net

Dans notre plateforme nous avons un gros site web Asp.Net (avec des webforms et web service) et il y a peu nous avons découvert Castle Monorail , qui est en gros un framework MVC pour Asp.Net genre Asp.Net MVC mais qui marche aussi avec le framework 2.0.

Pour pouvoir utilsier ce framework dans un site web asp.net voici les étapes :

1 - Copier les DLL de castle monorail


Castle.Components.Binder.dll

Castle.Components.Common.EmailSender.dll

Castle.Components.Common.TemplateEngine.dll

Castle.Components.Common.TemplateEngine.NVelocityTemplateEngine.dll

Castle.Components.Validator.dll

Castle.Core.dll

Castle.MonoRail.Framework.dll

Castle.MonoRail.Framework.Views.NVelocity.dll

Castle.MonoRail.ViewComponents.dll

NVelocity.dll

Certaine ne sont pas forcément tous le temps essentielle (notamment celles sur NVelocity).

2 - Configuration :


Tout se fait dans web.config

- Déclaration de la section de configuration
[sourcecode language="xml"]<section name="monorail" type="Castle.MonoRail.Framework.Configuration.MonoRailSectionHandler, Castle.MonoRail.Framework" />[/sourcecode]
- La configuration en elle-même
[sourcecode language="xml"]
<monorail>
<controllers>
<assembly>App_Code</assembly>
<assembly>Castle.Monorail.ViewComponents</assembly>

</controllers>
<viewEngines viewPathRoot="Views">
<add type="Castle.MonoRail.Framework.Views.NVelocity.NVelocityViewEngine, Castle.MonoRail.Framework.Views.NVelocity" />
</viewEngines>
</monorail>
[/sourcecode]

On remarque le
[sourcecode language="xml"]<assembly>App_Code</assembly>[/sourcecode]

Qui déclare l'assembly App_Code (celui crée par .net à partir du dossier App_Code du site web) qui contiendra nos controller (on peut ainsi importer des assembly d'autre projet en les ajoutant ici).

les HttpHandlers (pour interdire les accès direct au vm et rediriger les .rails vers Monorail)
[sourcecode language="xml"]<add verb="*" path="*.rails" type="Castle.MonoRail.Framework.MonoRailHttpHandlerFactory, Castle.MonoRail.Framework" />
<!--block direct user access to template files-->
<add verb="*" path="*.vm" type="System.Web.HttpForbiddenHandler" />
<add verb="*" path="*.boo" type="System.Web.HttpForbiddenHandler" />
<add verb="*" path="*.st" type="System.Web.HttpForbiddenHandler" />
[/sourcecode]

Et le http module
[sourcecode language="xml"]<add name="monorail" type="Castle.MonoRail.Framework.EngineContextModule, Castle.MonoRail.Framework" />[/sourcecode]


3 - IIS


Dans la console d'adminstration de IIS (IIS 6 pour moi)
-Il faut aller jusqu'a la racine du site web
-Click-droit sur la racine
-Properties
-Onglet Directory
-Bouton Configuration
-Double click sur la ligne de l'extension .aspx
-Copie le chemin de l'exécutable (quelque chose comme "C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll")
-"Cancel"
-Bouton "Add..."
-On colle le chemin dans la première text box
-".rails" dans la deuxième
-"verify that file exists" -> Décoché
- Ok , OK , OK

4 - TEST



Fichier TestMonorailController.cs à mettre dans le dossier App_Code (dans un sous dossier si besoin)
[sourcecode language="csharp"]
using Castle.MonoRail.Framework;

public class TestMonorailController : SmartDispatcherController
{
    public TestMonorailController()
    {
    }
    public void OnePage()
    {
        PropertyBag["toto"] = "TEST";
    }
}[/sourcecode]
Fichier OnePage.vm à mettre dans /Views/TestMonorail/ du site web
[sourcecode language="html"]$toto[/sourcecode]
Dans la navigateur on accède à
"http://laracinesdemonsite.com/TestMonorail/onePage.rails".
Et la on devrait voir s'afficher "TEST" .

Et voila. 

jeudi 23 septembre 2010

Ajouter une bibliothèque à l’intellisense javascript de Visual Studio 2010

Dans Visual Studio si par exemple j'ai un fichier fonction.js qui utilise prototype si je tape

"new Ajax."

Quand je demande l'intellisense (Ctrl + Espace), Visual Studio ne me propose que les fonctions partagées par tout les objets JavaScript.

Pour signifier à Visual Studio que j'utilise une bibliothèque, il faut :

- Ouvrir fonction.js avec l'éditeur de code source

- Ouvrir l'explorateur de solution

- Naviguer dans l'arborescence jusqu'à la bibliothèque utilisée

-"Drag'n droper" la bibliothèque dans l'éditeur de texte au début du fichier

Visual studio insèrera ce genre de choses :
/// <reference path="../prototype-1.6.0.3.js" />

Et l'intellisense marchera parfaitement

Exemple d'appel de l'intellisense JS de visual studio

Source :

http://msdn.microsoft.com/en-us/library/bb385682.aspx#Features

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