Mon premier pitch en D1A en Mars 1994
Mot de passe :
Accueil | 
Résultats du mot clé Google
03/09/2008
innerHTML ou appendChild, et performances sous Google Chrome

Pour ajouter des éléments dans du HTML, il y a deux écoles. L'ancienne, à la rache, avec le innerHTML et la nouvelle, pro, proche de ce qu'on peut faire en c# avec le appendChild.

Andrew Hedges a fait un petit comparatif de performances en fonction du navigateur et il en ressort qu'il n'est pas possible de privilégier l'une ou l'autre solution !

La manipulation de div dans un éléments 10 000 fois donne des résultats assez disparates. J'en ai profité pour ajouter dans le tableau le résultat sans appel avec Google Chrome.

 

  innerHTML DOM replacement innerHTML + DOM
Google Chrome Beta

179

265

245

Safari 3

109

104

96

Safari 2

489

849

457

Firefox 3b4

1588

1030

523

Firefox 2

1386

1019

401

IE 8b1

900

2131

844

IE 7

290

1275

475

IE 6

339

1880

373

Opera 9.27

266

847

675

Mots clés associés : Google Chrome Javascript  | Lien permanent | Laissez le premier votre commentaire
Publiée dans la zone Technologies
02/09/2008
Google Chrome, premières impressions

Fraichement mis en ligne, je viens à l'instant de télécharger et installer Google Chrome, le navigateur du célèbre moteur de recherche.

Installation simple, sans accro et premières navigations. Sur Gmail, l'affichage est plutôt rapide. Sur des sites chargés comme mlb.com, le gain de performance est plutôt significatif. Le rendu est très rapide, c'est assez impresionnant. J'ai un peu la même sensation que lorsque j'ai utilisé Opéra 9.

La page d'accueil montre les dernières navigations sous forme de widget. Utile ? Pas si sur !

Je regarde un peu sous le capot, le debugger Javascript à l'air assez puissant. Il faudra l'étudier de près.

Le rendu est assez fidèle, peu ou pas de différences avec des sites correctement designés pour IE ou Firefox.

Et le contenu multimédia ? Je vais sur cnn.com, vidéo. Un message m'indique que Flash est à installer. Le système de download de Chrome m'indique avec une bonne grosse flèche où je dois cliquer pour démarrer le téléchargement. On me demande aussi l'installation du wmvfirefoxplugin. Je m'éxécute et redémarre Chrome. Rien a faire ! Aucune vidéo ! Youtube devrait fonctionner quand même ! Ca marche, sauvé !

Netvibes fonctionne aussi. Les widgets se déplacent. La police gras du site est très pixellisée, c'est moche, peu être encore un petit effort sur le rendu HTML a faire sur Chrome.

Taquinons le goujon, allons sur le site Silverlight de Microsoft... Il me dit que mon navigateur n'est pas forcément compatible, j'en conviens... Je télécharge et installe Silverlight 2.0 Beta 2... F5.... Pas de bol, ça marche pas. Sur quiksilver-europe.com, les videos ne fonctionnent pas sauf le son !

Néanmoins, Google Chrome rempli pour moi les fonctions d'un navigateur... Simple et efficace, je retrouve l'aisance et la rapidité d'Opéra... que je n'utilise pourtant pas au quotidien.

 

Mots clés associés : Google Chrome  | Lien permanent | Laissez le premier votre commentaire
Publiée dans la zone Technologies
01/07/2008
La poursuite dans Bullitt Geocodée

Superbe film, pour un fan de grosses cylindrées américaines. J'adore les Ford Mustang et le film Bullitt.  Sur le site the laughing squid, ce superbe parallèle entre le film et sa poursuite entre la mustang Fastback et la dodge Charger et le géocodage sur Google Maps.

J'en profite pour vous signaler que la mustang et la Dodge Charger existent toujours.

La dodge Charger n'est rien d'autre qu'une Chrysler 300.

Et en ce qui concerne la Ford Mustang, on notera la magnifique série limitée Bullitt. Ford a tenu à rendre hommage au film en sortant un modèle à la couleur identique, oté du logo (comme dans le film). Le souci du détail va jusqu'a la sonorité du V8 telle que rendue à l'écran.


J'ai hate donc de payer mon malus tous les ans sur ma future mustang...

La poursuite est à suivre ici.

Mots clés associés : Mustang Ford Bullitt Charger Google  | Lien permanent | Laissez le premier votre commentaire
Publiée dans la zone L'insolite du Web
10/05/2007
Tutoriel : Mashup LiveSearch / GoogleSearch avec ASP.Net 2.0 et Ajax 1.0

Il y a quelques semaines, j'ai intégré GoogleSearch dans mon site grâce à son API. Le rendu est plutôt sympa et efficace, tout du moins pour les pages qui sont référencées par Google. Microsoft propose lui aussi son API pour le moteur de recherche Live.com. De mon esprit curieux, sort un mash-up plutôt inattendu avec les deux frères ennemis, d'où l'envie de marier les deux plutôt de que faire 2 zones de recherches.

Ce mini tutoriel vous présentera la manière dont ce mashup a été réalisé sur mon site internet avec :

  • Les pré requis
  • La création du WebService d'interrogation de MSN Live Search
  • Le code behind nécessaire
  • L'implémentation de GoogleSearch et de LiveSearch en Javascript

Les sources, libres de droits sont disponibles en téléchargement.

Les pré requis

1. Pour démarrer, vous devez référencer le WebService de recherche MSN sur http://soap.search.msn.com/webservices.asmx?wsdl

2. Votre Web.Config, doit contenir les éléments nécessaires à l'utilisation d'ASP.Net AJAX 1.0.

3. Quatre variables ont été mises dans le Web.Config à savoir :

4. Référencer la feuille de style de Google dans la page ASPX :

    <link href="http://www.google.com/uds/css/gsearch.css" type="text/css" rel="stylesheet"/>

5. votre page ASPX doit contenir un ScriptManager :

<asp:ScriptManager ID="ScriptManager1" runat="server" />

6. Votre fichier CSS doit absolument avoir le code suivant pour éviter d'avoir 2 zones de formulaires Google :

.gsc-control form.gsc-search-box   {display : none;}

 

Le WebService d'interrogation de MSN Live Search

Le webservice est localisé dans le fichier App_Code/WebService.cs. Pour que mon WebService soit accessible via mon javascript client, ne pas oublier de mettre l'attribut System.Web.Script.Services.ScriptService

 

[System.Web.Script.Services.ScriptService]

[WebService(Namespace = "http://www.laurentgeffroy.com/")]

[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]

public class WebService : System.Web.Services.WebService {

Pour la WebMethod, il faut également affecter l'attribut System.Web.Script.Services.ScriptMethod. L'utilisation est plutôt simple. On créé une nouvelle instance du WebService MSNSearchService auquel on affecte une requete. La requête est initialisée avec l'objet SearchRequest et les propriétés Query. La Query est modifiée pour limiter les recherches sur un domaine particulier. C'est également dans SearchRequest que vous affecterez la AppKey fournie.

Les résultats sont placés dans mes propres classes. Il est je pense possible d'utiliser directement le sourceResponse.Results comme valeur de retour. Mon but était de limiter la quantité de données à retourner au script coté client.

Votre WebService est construit ! Le voici en détail :

    [WebMethod(Description = "Récupère le résultat de la recherche sur le site actuel")]

    [System.Web.Script.Services.ScriptMethod]

    public LiveSearch.Resultats MsnLiveSearch(string p_search)

    {

        // Variable de retour

        LiveSearch.Resultats v_result = new LiveSearch.Resultats();

 

        // Nouvelle instance du WebService

        MSNSearchService _search = new MSNSearchService();

 

        SearchRequest _searchRequest = new SearchRequest();

        SearchResponse _searchResponse;

        Result[] sourceResults;

 

        try

        {

            SourceRequest[] _sr = new SourceRequest[1];

 

            // Recherche uniquement sur le Web

            _sr[0] = new SourceRequest();

            _sr[0].Source = SourceType.Web;

 

            // Construction de la recherche

            _searchRequest.Query = "site:" + ConfigurationManager.AppSettings["SiteWeb"] + " " + p_search;

            _searchRequest.Requests = _sr;

 

            // Fourniture du LiveAppID et de la culture

            _searchRequest.AppID = ConfigurationManager.AppSettings["LiveAppID"];

            _searchRequest.CultureInfo = "FR-fr";

 

            // Invocation et récupération du résultat

            _searchResponse = _search.Search(_searchRequest);

 

            foreach (SourceResponse sourceResponse in _searchResponse.Responses)

            {

                sourceResults = sourceResponse.Results;

 

                foreach (Result sourceResult in sourceResults)

                {

                    // Met les résultat dans mon propre objet

                    LiveSearch.Resultat _resultat = new LiveSearch.Resultat();

 

                    if ((sourceResult.Title != null) && (sourceResult.Title != String.Empty))

                        _resultat.Titre = sourceResult.Title;

 

                    if ((sourceResult.Description != null) && (sourceResult.Description != String.Empty))

                        _resultat.Description = sourceResult.Description;

 

                    if ((sourceResult.Url != null) && (sourceResult.Url != String.Empty))

                        _resultat.Url = sourceResult.Url;

 

                    v_result.Add(_resultat);

                }

            }

        }

        catch (Exception et)

        {

        }

        finally

        {

            sourceResults = null;

            _searchResponse = null;

            _searchRequest = null;

            _search = null;

 

        }

        return v_result;

    }

Le code-behind de votre page

Il est nécessaire de référencer le script Javascript de Google qui contient l'API Ajax. Il est bien entendu possible de le mettre en dur dans le code de la manière suivante :

        <asp:ScriptManager ID="ScriptManager1" runat="server">

            <Scripts>

                <asp:ScriptReference Path="http://www.google.com/uds/api?file=uds.js&amp;v=1.0&amp;key=maclé" />

            </Scripts>

        </asp:ScriptManager>

La même chose, en code managé :

ScriptReference SRef = new ScriptReference();

SRef.Path = "http://www.google.com/uds/api?file=uds.js&amp;v=1.0&amp;key=" + ConfigurationManager.AppSettings["GoogleApiKey"];

ScriptManager1.Scripts.Add(SRef);

On fournira également deux variables pour fournir au code Javacript le domaine de filtrage et le nom du site Web.

// Filtrage du site Web au niveau de la recherche

_restrictedDomain = ConfigurationManager.AppSettings["SiteWeb"];

// Nom du site Web

_siteName = ConfigurationManager.AppSettings["SiteNom"];

 

Le Javascript client

Avant de regarder en détail le javascript, attardons nous sur les div nécessaires pour la construction et la restitution des données :

            <div class="titre">Rechercher sur ce site</div><br />

            <div id="container_search_controls">

                <div id="google_search_form"></div>

                <div id="google_search_control"></div>

                <div id="live_search_container">

                    <div id="live_search_query"></div>

                    <div id="live_search_control"></div>   

                </div>

            </div>

  • google_search_for disposera de l'input de saisie et du bouton
  • google_search_control accueillera les résultats de la recherche
  • live_search_query sera initialisé avec le résumé de la recherche sur live.com
  • live_search_control comprendra les résultats obtenus sur live.com

 

On initialise deux variables issues du Code behind avec le domaine de recherche et le nom du site. Ma fonction LoadGoogleSearch créé une nouvelle instance de mon MyGoogleSearch qui construit l'interface. LoadGoogleSearch sera lancée plus loin.

        var _searchDomain = '<%= _restrictedDomain %>';

        var _siteName = '<%= _siteName %>';

 

                     

        function LoadGoogleSearch()

        {

            new MyGoogleSearch();

        }

MyGoogleSearch définit donc le contenu de mon interface. Il est nécessaire de passer par un GSearchForm si vous voulez intercepter le Submit et récupérer les données saisies dans l'input. On utilisera le setOnSubmitCallback pour intercepter le submit du formulaire et intégrer nos propres traitements. Les restrictions de recherche et apparances sont à initialiser dans l'instance de GwebSearch et GsearcherOptions .

        function MyGoogleSearch()

        {

            // Formulaire de saisie

            var sFormDiv = document.getElementById("google_search_form");

            // Zone de résultat

            var resultDiv = document.getElementById("google_search_control");

 

            this.searchControl = new GSearchControl();

            this.searchForm = new GSearchForm(true, sFormDiv);

 

            // Sur le submit

            this.searchForm.setOnSubmitCallback(this, MyGoogleSearch.prototype.onSubmit);

            this.searchForm.setOnClearCallback(this, MyGoogleSearch.prototype.onClear);

 

            var searcher = new GwebSearch();

            var options = new GsearcherOptions();

 

            // Limite la recherche au domaine

            searcher.setSiteRestriction(_searchDomain);

           

            // Personnalise le label de résultat

            searcher.setUserDefinedLabel(_siteName);

           

            // Ouvre le résultat

            options.setExpandMode(GSearchControl.EXPAND_MODE_OPEN);

            // Résultat long

            this.searchControl.setResultSetSize(GSearch.LARGE_RESULTSET);

            // Liens vers une nouvelle page

            this.searchControl.setLinkTarget(GSearch.LINK_TARGET_BLANK);           

            // Ajoute le Searcher

            this.searchControl.addSearcher(searcher, options);

           

            // Construit l'interface

            this.searchControl.draw(resultDiv);

 

        }

La fonction interceptant le submit de la recherche Google lance donc ma requête sur Google et sur Live.com gràce à la fonction LiveSearchBuilder en prenant soin de récupérer la chaine saisie. Le rendu des réponses de Google est fait automatiquement par l'API Ajax de ce dernier.

        MyGoogleSearch.prototype.onSubmit = function(form) {

            var query = form.input.value;

            if (query && query!= "")

            {

                // Exécute la recherche

                this.searchControl.execute(query);

                // Lance la recherche Live

                LiveSearchBuilder(query);

            }

            return false;

        } 

Ma fonction LiveSearchBuilder() nettoye d'abord un éventuel résultat précédent. On utilisera ensuite le Framework Ajax pour consommer notre WebService qui récupère la réponse dans OnMsnLiveSucceeded().

        function LiveSearchBuilder(p_query)

        {

            var _objC = document.getElementById("live_search_query");

            _objC.style.visibility = "visible";

           

            var _obj = document.getElementById("live_search_control");

           

            if (_obj != null)

            {

                // Efface le résultat précédent           

                if (_obj.childNodes.length > 0)

                {

                    for(x=0; x < _obj.childNodes.length; x++)

                    {

                        _obj.removeChild(_obj.childNodes[x]);

                    }

                }

               

            }

 

            // Invoque le WebService

            Sys.Net.WebServiceProxy.invoke("webservice.asmx",

                                            "MsnLiveSearch",

                                            false,

                                            { p_search : p_query},

                                            OnMsnLiveSucceeded,           

                                            OnMsnLiveFailed,

                                            null);

        }

 

La fonction OnMsnLiveSucceeded() récupère la réponse du WebService dans result et fait le rendu dans l'interface.

       

        // Si la requete à fonctionné

        function OnMsnLiveSucceeded(result, eventArgs)

        {

            // Affiche les résultats

            var out = document.getElementById("live_search_control");

             

            var i = 0;

            if (result.length > 0)

            {

                var _output = document.createElement("div");

               

  

                if (result.length > 1)                            

                    document.getElementById("live_search_query").innerHTML = result.length + " résultats sur LIVE.COM";

                else

                    document.getElementById("live_search_query").innerHTML = result.length + " résultat sur LIVE.COM";

                  

                for(i=0; i< result.length; i++)

                {

                    var _link = document.createElement("a");

                    _link.href = result[i].Url;

                    _link.target = "_blank";

                    _link.innerHTML = result[i].Titre;

                   

                    _output.appendChild(_link);

                   

                    var _desc = document.createElement("div");

                    _desc.className = "live_description";

                    _desc.innerHTML = result[i].Description;

                   

                    _output.appendChild(_desc);

                }

                out.appendChild(_output);

            }

            else

            {

                document.getElementById("live_search_query").innerHTML = "Aucun résultat sur LIVE.COM";

            }

           

        }

Enfin, ce morceau de code construit la zone de recherche :

        GSearch.setOnLoadCallback(LoadGoogleSearch);

Ne reste plus qu'a lancer votre page default.aspx...

Pour en savoir plus

Mots clés associés : Google LiveSearch Microsoft Ajax ASP.Net  | Lien permanent | Laissez le premier votre commentaire
Publiée dans la zone Tutoriels .Net
03/05/2007
Terrains de Baseball et Softball de France : La carte

J'ai décidé d'héberger sur mon site la carte des terrains de baseball et softball de France. Pour cela, je m'appuie sur la très sympathique API de GoogleMaps.

4 choses à voir ensemble :

1. La géolocalisation d'un terrain : 

L'objectif est de fournir aux acteurs du baseball et du softball en France une carte précise des terrains. Que votre zone soit couverte finement par GoogleMaps ou pas, peu importe. En mode Carte, il sera très facile à vos visiteurs de préparer son voyage. Rendez vous sur cette page. Zoomez sur la carte, trouvez votre terrain. Cliquez alors sur la zone que vous avez géolocalisée. Si vous vous êtes trompés, recliquez sur le marqueur pour l'effacer.

Dès que c'est ok, remplissez le formulaire. Je le validerai rapidement.

2. La visualisation sur laurentgeffroy.com

La page suivante restitue les terrains qui ont été validés.

3. La visualisation sur GoogleEarth

Cliquez sur le fichier kml pour ouvrir GoogleEarth et naviguer avec le client riche.

4. L'intégration sur votre propre site

Le code Javascript suivant est copier dans votre propre site web et profitez de la carte dans votre propre application. N'oubliez pas de récupérer votre APIKey GoogleMaps pour l'utilisée avec votre domaine.

 

<html>
   <head>
      <script src="http://maps.google.com/maps?file=api&amp;v=2.x&amp;key={MON API KEY GOOGLE DEPENDANTE DU DOMAINE}" type="text/javascript"></script>
   </head>
   <body> 

<div id="google_map_viewer"></div>

<script type="text/javascript">
    //<![CDATA[
    var hauteur = '400px';
    var largeur = '400px';
    document.getElementById("google_map_viewer").style.width = largeur;
    document.getElementById("google_map_viewer").style.height= hauteur;
    var map;
    var geoXml = new GGeoXml("http://www.laurentgeffroy.com/params/GoogleMaps/5dfbdc88-d9f2-411f-a92d-e9f338ec0d93.kml");

    function GoogleMarkerLoader()
    {
   
        if (GBrowserIsCompatible()) {
            map = new GMap2(document.getElementById("google_map_viewer"));
            map.addControl(new GLargeMapControl());
            map.addControl(new GMapTypeControl());
           
            // Centre au milieu de la France
            var point = new GLatLng(47.129951,0.878906);
            map.setCenter(point, 6);
            map.addOverlay(geoXml);
        }
    }
   
    setTimeout("GoogleMarkerLoader()", 1000);
    //]]>
</script>


             
   </body>
</html>

Mots clés associés : Google Maps Baseball  | Lien permanent | Laissez le premier votre commentaire
Publiée dans la zone Baseball [FR]
20/04/2007
Tutoriel : PicasaNet et Composant Ajax



Droit de diffusion et copyrights :

Ce tutoriel ne peut être diffusé sur d’autres sites Web ou tout autre support sans l’autorisation préalable de son auteur. L’utilisation des sources est totalement libre de droits. Toutes les marques citées appartiennent à leurs auteurs, en particulier les marques Google, Picasa, ainsi que leurs logos respectifs sont des marques déposées par Google Inc.

Avant propos :

Cela fait bientôt un an que j’ai découvert  le framework Atlas, renommé ASP.Net Ajax 1.0. La richesse de cette technologie offre de nombreuses voies pour des tutoriels et la sortie de Picasa2 me permet d’aborder sur un cas concret. Début Janvier 2007, me voila en route pour faire un SlideShow en Ajax. 3 jours plus tard, le voici disponible dans la AjaxControlToolkit, réduisant à néant mes premières approches !!! Restait à l’améliorer et à l’adapter quelque peu.

Picasa dispose donc d’une API assez simple, qui s’attaque par une requête http en GET toute simple. L’exposition se fait via un flux rss, assez verbeux et qu’il convient de nettoyer. Nous aborderons ici des points techniques que j’ai pu déjà exposer lors de précédents tutoriels. Mais mieux vaut se répéter et disposer d’un tutoriel complet.

Ainsi nous aborderons les points suivants :

-          Récupération du flux XML via un HttpResponse

-          Transformation du flux via XSL

-          Désérialisation des données dans une classe .Net

-          L’utilisation du composant PicasaNet

Puis coté Ajax

-          Le WebService permettant de récupérer les requêtes

-          Le Toolkit Ajax et son fonctionnement

Le tutoriel s’articule sur une solution disposant :

-          Du projet PicasaNet qui permet d’interagir avec l’API de Picasa et qui dispose d’un AjaxControlToolkit

-          Un projet Web qui exploite le composant Ajax et l’API de PicasaNet

1.  PicasaNet

1.1       Qu’est-ce que c’est ?

PicasaNet est un composant gratuit et libre de droits qui vous permet d’interroger l’API de Google Picasa. Les données récupérées sont stockées dans des classes propres à PicasaNet, ce qui simplifie grandement l’accès, la manipulation et d’utilisation des informations fournies par Google Picasa. Le mode de récupération est plutôt évolutif. En ayant accès aux sources vous pouvez parfaitement enrichir les informations récupérées par PicasaNet.

La récupération est assez originale car elle se base sur une transformation XSL pour se caler aux structures des classes PicasaNet. Ce n’est peut être pas forcément la manière la plus efficace de faire, mais elle permet d’aborder une méthode différente et techniquement plus intéressante.

projetPicasaNet.jpg

Le dossier AjaxToolkit dispose du composant Ajax qui permet de restituer le contenu d’un WebAlbum Picasa.

Notez que le fichier JS doit absolument être une ressource incorporée. Pour cela, sélectionnez votre fichier, puis dans l’écran de propriétés, Action de génération choisissez « Ressource incorporée ».

Les dossiers Collections et Elements disposent de classes qui permettent de stocker les données issues de Picasa.

Response dispose des classes de base à utiliser. ListOfAlbums pour disposer de l’ensemble des albums d’un compte et PictureAlbum pour avoir l’ensemble des images d’un album.

Dans Xsl vous trouverez les deux feuilles de style qui permettent de transformer le flux RSS Picasa vers la structure PicasaNet. Ces feuilles de styles devront être déployées manuellement sur le site Web.

Picasa.cs est la classe de base à instancier pour utiliser le composant.

Il est à préciser que vous devez avoir installer l’environnement AJAX 1.0 pour modifier ou compiler ce composant.

Rendez vous sur http://ajax.asp.net/downloads/default.aspx?tabid=47 et installez :

-          ASP.Net 2.0 AJAX Extensions

-          ASP.Net AJAX Control Toolkit

-          ASP.Net Ajax Futures CTP

1.2       La récupération des flux XML

1.2.1     Tester son application avec ces propres URL

Il vous est bien entendu possible de tester vos propres Url de flux RSS Picasa notamment lorsque vous être en mode déconnecté. L’objet Picasa dispose d’une propriété AllowUrlChanging que vous pouvez mettre à True. Cela permet ensuite d’être en mesure de fournir vos propres Url locales ou distantes en modifiant ensuite les propriétés SetGoogleAlbumsListUrl (pour le flux de liste des albums) et SetGoogleAlbumUrl (pour le flux d’un album). Si ces propriétés ne sont pas initialisées, l’API prendra l’Url par défaut de Google Picasa, à laquelle il ajoutera les données variables comme le compte Picasa et éventuellement le numéro d’Album.

1.2.2     La liste des albums

La méthode GetAlbumsList() vous permet de récupérer dans une classe ListOfAlbums l’ensemble des albums d’un compte Google Picasa déterminé.

La première étape consiste à vérifier si le compte Picasa est bien fourni. C’est la méthode privée CheckRequiredArgs qui s’en charge. Elle ne vérifie la présence des données obligatoires que si vous laissez à l’API le soin de définir les Url de destination (voir chapitre 1.2.1). En fonction, BuildRequestForListOfAlbums construira la requête dans la variable _request qui est une variable membre.

                if (CheckRequiredArgs(_user))

                {

                    // Build httpRequest set _request variable

                    BuildRequestForListOfAlbums();

                    // Send Request the Google Picasa

                    HttpWebResponse v_response = DoGetResponse(_request);

DoGetResponse  récupère le contenu du flux RSS. Il s’agit d’invoquer un HttpWebRequest sur l’url construite. Il aurait été possible d’utiliser ici directement la variable membre _request plutôt qu’un paramètre dans la méthode.

        private HttpWebResponse DoGetResponse(string p_url)

        {

            HttpWebRequest v_request = null;

            HttpWebResponse v_response = null;

            // Initialise the web request

            v_request = (HttpWebRequest)HttpWebRequest.Create(p_url);

            v_request.UserAgent = USERAGENT;

            v_request.Timeout = _timeOut;

            v_request.KeepAlive = false;

            v_request.Method = "GET";

            if (Proxy != null)

                v_request.Proxy = Proxy;

            try

            {

                // Get response from the internet

                v_response = (HttpWebResponse)v_request.GetResponse();

            }

            catch (WebException ex)

            {

throw new Exception("DoGetResponse:Error while requesting url " + p_url + ". Error Status " + ex.Status + " " + ex.Message);

            }

            catch (Exception exc)

            {

                throw new Exception("DoGetResponse:Error : " + exc.Message);

            }

            return v_response;

        }

De retour dans notre méthode appelante, je place la réponse ainsi obtenue dans un StreamReader, car il me faut encore transformer le format RSS Picasa dans une structure PicasaNet que je pourrais désérialiser. La méthode XslTransform  s’occupe à la fois de la transformation XSL mais également de la désérialisation. Ce point technique est détaillé dans le chapitre 1.3. Si la transformation et la désérialisation se sont bien déroulées, la variable de retour v_result est initialisée avec _albumList qui comporte la liste des albums. Cette variable membre est initialisée par la méthode XslTransform.

                    // I have a response

                    if (v_response != null)

                    {

                        // Put the XML response into a StreamReader

                        v_sr = new StreamReader(v_response.GetResponseStream());

// Ready to be transformed while the appropriate XSL Style Sheet

if (XslTransform(v_sr.BaseStream, BuildXsltPath(TransformationType.ALBUMS), TransformationType.ALBUMS))

                            v_result = _albumList;

                    }

1.2.3     Un album en particulier

La récupération d’un album en particulier fonctionne de la même manière que la récupération d’une liste. Si l’Url est définie par l’application, le numéro de l’album est obligatoire. On utilisera la méthode GetAlbum. Cette méthode est surchargée et permet de passer le numéro de l’album via l’objet PicasaNet.Picasa ou bien en paramètre de la méthode.

1.3       La transformation des flux

La méthode privée XslTransform attend 3 arguments :

-          Le streamReader du flux RSS de Google Picasa

-          Le chemin de la feuille de style

-          Le type de transformation via une énumération

Le chemin de le feuille de style est initialisé à l’instanciation de l’objet PicasaNet.Picasa. Le nom de la feuille de style est fixe pour chaque type de transformation et ne doit pas être modifiée.

La transformation effectuée, vient ensuite la désérialisation. En fonction du type (p_type) , la méthode procède donc à la désérialisation et initialise la bonne variable membre.

                // Deserialized the transformed XML

                switch (p_type)

                {

                    case TransformationType.ALBUMS:

                        // For the list of Albums

                        v_serializer = new XmlSerializer(typeof(ListOfAlbums));

                        _albumList = (ListOfAlbums)v_serializer.Deserialize(v_xreader);

                        break;

                    case TransformationType.ALBUM:

                        v_serializer = new XmlSerializer(typeof(PictureAlbum));

                        _album = (PictureAlbum)v_serializer.Deserialize(v_xreader);

                        break;

                }

                v_result = true;

1.4       L’utilisation du composant

Le projet Web fournit 2 exemples, l’un pour la liste des albums, l’autre pour l’accès à un album en particulier. Pour chacun des cas, deux pages permettent d’afficher le flux XML. :

-          Récupération d’un flux local, transformation XSL et affichage direct de la transformation

-          Récupération d’un flux distant chez Google Picasa, transformation XSL, désérialisation et resérialisation, pour le fun….

L’utilisation de l’une ou l’autre est possible en ajoutant ou supprimant un argument fictif dans l’url. La requête avec argument interrogera directement Google Picasa.

Pour restituer le flux XML, on se place maintenant sur la solution Web et les pages ListOfAlbums.aspx et Album.aspx

Si vous utilisez des Thèmes dans votre application Web, veillez bien à ajouter les attributs Theme, SylesheetTheme, EnableTheming à vos pages qui doivent retourner un flux XML ainsi que les attributs ResponseEncoding et ContentType :

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="ListOfAlbums.aspx.cs" Inherits="ListOfAlbums" ContentType="text/xml" ResponseEncoding="utf-8" Theme="" StylesheetTheme="" EnableTheming="false" %>

1.4.1     Liste des albums

Dans le code behind de la page ListOfAlbums.aspx on dispose du code qui d’une part fait une simple transformation des fichiers locaux (disponibles dans le jeu de test) et d’autre part utilise l’API PicasaNet, toujours instanciée avec le compte Picasa et le chemin des feuilles de styles, ces données étant stockées dans le Web.Config. Dans le second cas, on procède à une sérialisation de la classe ListOfAlbums vers le Response.OutputStream .

    protected void Page_Load(object sender, EventArgs e)

    {

        Response.ContentType = "text/xml";

        Response.ContentEncoding = System.Text.Encoding.UTF8;

        string _out = string.Empty;

  PicasaNet.Picasa picasa = new     PicasaNet.Picasa(ConfigurationManager.AppSettings["GooglePicasaUser"], ConfigurationManager.AppSettings["XslPath"]);

        if (Request.QueryString.Count == 0)

        {

            // First solution

            // Loading 2 files, running transformation

            string _xsl = "http://localhost/WebPicasa/xslt/ListOfAlbums.xslt";

            string _xml = "http://localhost/WebPicasa/xmlsamples/Albums.xml";

            _out = picasa.RunXmlXslStandaloneTransformation(_xml, _xsl);

            Response.Write(_out);

        }

        else

        {

            // Second solution

            // Loading Picasa XML File, Deserialization and Serialization for the fun !

            PicasaNet.ListOfAlbums _liste = picasa.GetAlbumsList();

            XmlSerializer serializer = new XmlSerializer(typeof(PicasaNet.ListOfAlbums));

            serializer.Serialize(Response.OutputStream, _liste);

        }

        picasa.Dispose();

        Response.End();

    }

1.4.2     Album spécifique

Pour un album spécifique, la technique est quasiment identique à celle du chapitre précédent. On s’attardera plus sur l’utilisation de l’API de PicasaNet, disponible dans le code behind de la page Album.aspx. L’exemple nettoyer montre bien d’une part l’instanciation de l’objet PicasaNet.Picasa avec ces valeurs de base (compte et chemin des feuilles de style) mais surtout dans un second temps l’appel de GetAlbum avec l’album a récupérer, dont l’ID est stockée dans le Web.Config.

        Response.ContentType = "text/xml";

        Response.ContentEncoding = System.Text.Encoding.UTF8;

        string _out = string.Empty;

        PicasaNet.Picasa picasa = new PicasaNet.Picasa(ConfigurationManager.AppSettings["GooglePicasaUser"], ConfigurationManager.AppSettings["XslPath"]);

       // Second solution

       // Loading Picasa XML File, Deserialization and Serialization for the fun

       PicasaNet.PictureAlbum _album = picasa.GetAlbum(ConfigurationManager.AppSettings["GooglePicasaDemoAlbumID"]);

       XmlSerializer serializer = new XmlSerializer(typeof(PicasaNet.PictureAlbum));

       serializer.Serialize(Response.OutputStream, _album);

        picasa.Dispose();

        Response.End();

Comme vous pouvez le voir, l’utilisation de l’API de PicasaNet est très simple, l’API de Google Picasa étant elle aussi très basique. Il est bien entendu possible d’enrichir les classes de stockage de PicasaNet, d’une part en ajouter des accesseurs publics aux classes de structures, mais également en enrichissant les différentes feuilles de styles qui doivent reflèter fidèlement la structure des classes.

Comme vous avez pu vous en rendre compte, certains attributs sont ajoutés aux accesseurs publics pour les transformer en attributs XML ou voir renommer des accesseurs coté XML. Ainsi, tous les accesseurs commencent par une majuscule, par contre, ceux transformés en attributs sont mis coté XML en minuscules.

Mais attention dans l’utilisation des données dans le composant AJAX : Dans la classe Album, j’ai un accesseur Id qui est mis en Attribut sous la forme id. Lors de l’utiliation de mon WebService qui va resérialiser cette classe, il mettra bien id dans le résultat de la requête SOAP. Cependant, dans le composant AJAX, lorsque vous voudrez parcourir votre flux XML, il conserve le nom original de l’accesseur, soit Id. Ce petit désagrément m’a valu un bon mal de crane.

    [Serializable]

    public class Album

    {

        #region PRIVATE MEMBERS

        private string _id = string.Empty;

        private string _url = string.Empty;

        private string _name = string.Empty;

        private string _description = string.Empty;

        private bool _public = false;

        private int _qty = 0;

        #endregion

        #region PUBLIC MEMBERS

        /// <summary>

        /// Album ID

        /// </summary>

        [XmlAttribute(DataType = "string", AttributeName = "id")]

        public string Id

        {

            get { return _id; }

            set { _id = value; }

        }

2.  Le contrôle Ajax

2.1 Les relations Extender / Javascript

L’un des principaux avantages de ce framework est la capacité à étendre des contrôles serveurs et de les manipuler via du code Javascript. La certaine homogénéité des navigateurs internet et les gros efforts notamment de Microsoft pour se rapprocher des normes du W3C ont quelque peu réhabilité le Javascript qui a eu sa période de gloire dans les années 2000 et qui depuis tombait en désuétude.

Dès lors l’Extender ne fait que s’appuyer sur des contrôles serveurs, les exploitent et permet de gérer le rendu coté client et non plus serveur.

Entre l’Extender et le Javascript, il existe forcemment des liens forts et une rigueur de nommage est nécessaire d’une part pour que votre application fonctionne et d’autre part pour éviter de se perdre dans toutes ces variables. Le professionnalisme du développement des composant de l’Ajax ControlToolkit sont je pense une bonne base pour tout développeur qui souhaite construire son propre contrôle.

Dans le projet PicasaNet, examinons déjà le fichier PicasaSlideShowExtender.cs. L’attribut ClientScriptResource permet de faire le lien avec le JavaScript. Attention au nommage. Il s’agit ici de mettre d’abord le Namespace de l’Assembly, suivi par des points du chemin dans l’arborescence du projet. J’ai volontairement mis un nom différent du namespace à mon dossier comportant le Contrôle Ajax. Mon contrôle Ajax est dans le namespace PicasaNet.PicasaAjaxToolkit. Le chemin de la ressource n’est pas PicasaNet.PicasaAjaxToolkit.PicasaSlideShoxBehavior.js mais plutôt PicasaNet.AjaxToolkit.PicasaSlideShowBehavior.js car mon contrôle est dans le répertoire « AjaxToolkit ».

    [Designer("PicasaNet.PicasaAjaxToolkit.PicasaSlideShowDesigner, AjaxControlToolkit")]

    // AssemblyName [.] Js File path replacing '/' by '.'

    [ClientScriptResource("PicasaNet.PicasaAjaxToolkit.PicasaSlideShowBehavior", "PicasaNet.AjaxToolkit.PicasaSlideShowBehavior.js")]

    [TargetControlType(typeof(System.Web.UI.WebControls.Image))]

    [RequiredScript(typeof(BlockingScripts))]

    [RequiredScript(typeof(CommonToolkitScripts))]

    [RequiredScript(typeof(AnimationScripts))]

    public class PicasaSlideShowExtender : ExtenderControlBase

    {

Un ExtenderControlProperty est tout simplement une propriété de votre contrôle Ajax. Une valeur par défaut peut être assignée, ici 3. Le ClientPropertyName est le nom de la variable coté JavaScript. Mettez le même nom que votre propriété, mais avec la première lettre en minuscules. Les accesseurs Get et Set utiliseront obligatoirement les GetPropertyValue et SetPropertyValue fournis par l’Extender.

        [ExtenderControlProperty]

        [DefaultValue(3)]

        [ClientPropertyName("thumbnailImages")]

        public int ThumbnailImages

        {

            get

            {

                return GetPropertyValue("ThumbnailImages", 3);

            }

            set

            {

                SetPropertyValue("ThumbnailImages", value);

            }

        }

Coté Javascript, notre thumbnailImages ce retrouve de la façon suivante, toujours précédé d’un get_thumbnailImages et set_thumbnailImages. Notez que l’initialisation via le set_thumbnailImages se fait grâce au this.raisePropertyChanged('thumbnailImages') qui reprend le nom de nom variable coté client. La valeur est stockée coté client dans le this._thumbnailImages initialisé au début du script. Ici la variable est précédée du underscore pour une meilleure lisibilité.

    get_thumbnailImages : function() {

        /// <value type="Number" integer="true" mayBeNull="true"/>           

        return this._thumbnailImages;

    },     

    set_thumbnailImages : function(value) {

        if (this._thumbnailImages != value) {

            this._thumbnailImages = value;

            this.raisePropertyChanged('thumbnailImages');

        }

    },

Si l’on retourne maintenant à notre Extender, vous souhaitez peut être étendre pas seulement des variables mais également des contrôles comme des Panel, Image, LinkButton… Dans l’exemple ci-dessous, on étend un Panel, type comme un WebControl. Vous pouvez ici être plus précis et mettre le type exact de votre contrôle.

        [ExtenderControlProperty]

        [DefaultValue("")]

        [IDReferenceProperty(typeof(WebControl))]

        [ClientPropertyName("thumbnailPanelID")]

        public string ThumbnailPanelID

        {

            get

            {

                return GetPropertyValue("ThumbnailPanelID", "");

            }

            set

            {

                SetPropertyValue("ThumbnailPanelID", value);

            }

        }

Coté Javascript, le fonctionnement est identique, avec les accesseurs get_ et set_ :

    get_thumbnailPanelID : function() {

        /// <value type="String" mayBeNull="true">   

        /// ID of the label that describes the current slide.

        /// </value>

        return this._thumbnailPanelID;

    },

    set_thumbnailPanelID : function(value) {

        if (this._thumbnailPanelID != value) {

            this._thumbnailPanelID = value;

            this.raisePropertyChanged('thumbnailPanelID');

        }

    },

Cependant, il vous faudra une autre variable car this._thumbnailPanelID dispose uniquement de l’ID du contrôle. Il est donc nécessaire à l’initialisation du contrôle coté Javascript de définir une variable qui sera vraiment votre objet, ici un <div> puisque c’est un Panel :

        if (this._thumbnailPanelID)

        {

            this._pthumbnail = document.getElementById(this._thumbnailPanelID);

        }

2.2 Les principaux changements par rapport au SlideShow classique de l’AjaxControlToolkit

Les principales évolutions portent sur les points suivants :

-          L’ajout d’arguments au WebService permettent la récupération des Images du WebAlbum. Google Picasa ne permet aujourd’hui de récupérer que les images d’un album mais des évolutions laissent penser que l’on pourrait obtenir des images par rapport au tag. A ce jour, cela ne fonctionne pas dans leur API et de plus je ne vois pas ou dans l’interface graphique l’on peut ajouter des mots clés !

L’appel du WebService est géré de cette manière. Le 3eme paramètre dispose des arguments du WebService entre ‘{‘ et ‘}’. Les arguments doivent correspondre à ceux du WebService.

        Sys.Net.WebServiceProxy.invoke(

                this._slideShowServicePath,

                this._slideShowServiceMethod,

                false,

                { picasaAction : this._paramAction, picasaParam: this._paramValue },

                Function.createDelegate(this, this._initSlides),

                null,

                null);

-          La disponibilité d’un visualisateur de vignettes, suivant pas à pas l’image en cours. Le visualisateur est initialisé à la récupération des données XML et mis à jour à chaque changement d’images.

-          L’enrichissement du texte de l’image qui permet en fonction d’un paramètre de télécharger ou non l’image originale.

-          La mise en œuvre d’un résumé, avec l’icône de l’album, sa description et son titre. Un lien permet un accès direct à l’album.

-          L’étendue des images disponible qui va de la vignette jusqu’au fichier original en passant par un aperçu de taille moyenne.

2.3 L’accès aux données XML en Javascript

A chaque chargement de l’image, la fonction this.updateImage  est exécutée. On transmet alors uniquement l’image a afficher via un this._xml.Pictures[this._currentIndex]. this._xml représente la racine du flux XML issu du WebService.

    _onImageLoaded : function(e) {

        /// <summary>

        /// Image loaded handler.

        /// </summary>

        /// <param name="e" type="Sys.UI.DomEvent" mayBeNull="false"/>  

        /// <returns />     

        this.updateImage(this._xml.Pictures[this._currentIndex]);

        this.resetButtons();       

        this._cacheImages();

    },

La ou cela devient étrange c’est dans la récupération des autres données. Dans la fonction updateImage, on récupère l’image réduite et son titre. Or dans le flux XML, les données sont des attributs nommés medium et title !! Bien que la sérialisation ait modifiée l’apparence du flux XML dans le WebService, son utilisation coté client en Javascript n’en tient pas rigueur ! Ce qui est plus étrange c’est que le contrat WSDL ne mentionne nullement les noms des accesseurs publics de mes classes .Net.

            this._elementImage.src = value.ResizedUrl;           

            this._elementImage.alt = value.Title;

Pire, si vous décidez de renommer la collection de Picture via XmlArray et XmlArrayItem, il devient alors impossible d’accéder aux nœuds coté Javascript.

2.4 Les prérequis

Vous devrez tout d’abord installer les composants ASP.Net AJAX disponibles à sur http://ajax.asp.net/downloads/default.aspx?tabid=47 et précisés dans le point 1.1 de ce tutoriel.

Par la suite, votre Web.Config doit comporter un certain nombre d’informations pour faire fonctionner les composants AJAX

Dans le nœud <configuration> :

      <configSections>

            <sectionGroup name="system.web.extensions" type="System.Web.Configuration.SystemWebExtensionsSectionGroup, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">

                  <sectionGroup name