Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

Atteint de JavaScriptite Aiguë [Cyril Durand]

Expert ASP.net Ajax et WCF, Cyril Durand parle dans son blog de point techniques sur ASP.net, ASP.net Ajax, JavaScript, WCF et .net en général. Cyril est également consultant indépendant, n'hésitez pas à le contacter pour de l'assistance sur vos projets

Actualités

  • Blog de Cyril DURAND, passionné de JavaScript, Ajax, ASP.net et tout ce qui touche au developpement Web Client-Side.

    N'hésitez pas à me contacter pour vos projets .net : architecture, accompagnement, formation, ...

    View Cyril Durand's profile on LinkedIn
    hit counters


    Expertise Commerce server et BizTalk

Référencement et UpdatePanel : la solution CrawlableLinkButton

Les UpdatePanels sont très agréables pour l'utilisateur puisque, bien utilisés, ils permettent d'avoir une expérience utilisateur plus fluide. Pour arriver à ce résultat, ils utilisent une requête XMLHttpRequest (requête Ajax) qui n'est pas référençable par les moteurs de recherche.

Comment utiliser les UpdatePanels sans sacrifier son référencement ? 

Pour qu'un utilisateur puisse utiliser les résultats du moteur de recherche, il faut que le contenu soit accessible à partir d'une requête GET, lorsque l'utilisateur clique il faut qu'il arrive directement sur ce qui l'intéresse, ce n'est pas le cas si on utilise les UpdatePanels avec un LinkButton.

Prenons un exemple : une page qui liste les processus en cours sur la machine et qui affiche le détail du processus sélectionné :

<script type="text/C#" runat="server"> void Page_Load(Object sender, EventArgs e) { if (!Page.IsPostBack) { BindData(); } } private System.Diagnostics.Process _currentProcess; public System.Diagnostics.Process CurrentProcess { get { if (_currentProcess == null) { int pid = -1; if (Page.IsPostBack) { if (ViewState["PID"] != null) { pid = (int)ViewState["PID"]; } } else { int.TryParse(Request.QueryString["PID"], out pid); } if (pid > -1) { _currentProcess = Processes.Find(delegate( System.Diagnostics.Process process){ return process.Id == pid; }); } else { _currentProcess = Processes[0]; } } return _currentProcess; } set { ViewState["PID"] = value.Id; _currentProcess = value; } } private static List<System.Diagnostics.Process> _processes; public static List<System.Diagnostics.Process> Processes { get { // Ne faites pas ça, c'est pour l'exemple mais attention // c'est pas thread safe ... if (_processes == null) { _processes = new List<System.Diagnostics.Process>( System.Diagnostics.Process.GetProcesses()); } return _processes; } } void gvProcess_SelectedIndexChanged(object sender, EventArgs e) { // ca aussi c'est mal, c'est pour simplifier l'exemple CurrentProcess = Processes[gvProcess.SelectedIndex]; } void BindData() { gvProcess.DataSource = Processes; gvProcess.DataBind(); } </script> <asp:Content ID="Content1" ContentPlaceHolderID="CPH1" runat="Server"> <asp:UpdatePanel runat="server" UpdateMode="Conditional" > <ContentTemplate> <%=CurrentProcess.ProcessName %> </ContentTemplate> <Triggers> <asp:AsyncPostBackTrigger ControlID="gvProcess" /> </Triggers> </asp:UpdatePanel> <asp:GridView runat="server" ID="gvProcess" AutoGenerateColumns="false" OnSelectedIndexChanged="gvProcess_SelectedIndexChanged"> <Columns> <asp:CommandField ShowSelectButton="true" /> <asp:BoundField DataField="ProcessName" /> <asp:BoundField DataField="VirtualMemorySize" /> </Columns> </asp:GridView> </asp:Content>

Cette page fonctionne parfaitement, mais regardons le code html généré au niveau d'une ligne d'un gridview.

<tr class="AspNet-GridView-Alternate"> <td><a href="javascript:__doPostBack('ctl00$CPH1$gvProcess','Select$15')">Select</a></td> <td>WebDev.WebServer</td> <td>283324416</td> </tr>

Le détail de ce processus ne peut pas être indexé par un robot. Même si un robot était capable d'exécuter JavaScript et donc de lire le détail du processus, comment ferait-il ressortir ce résultat ? Lorsque l'utilisateur fais une recherche il veut voir directement le contenu qui l'intéresse : il faut que la contenu soit accessible à partir d'une URL.

Comment contourner le problème ? L'idée est d'exécuter le postback donc du JavaScript pour les clients riches tout en laissant une vrai url pour les robots.

Ainsi la ligne plus haut se transformerait en :

<tr class="AspNet-GridView-Alternate"> <td> <a href="temp.aspx?PID=1092" onclick="void(__doPostBack('ctl00$CPH1$gvProcess$ctl17$ctl00',''));return false;"> Select </a> </td> <td>WebDev.WebServer</td> <td>285884416</td> </tr>

Pour arriver à ce résultat, j'ai créé un contrôle héritant de LinkButton : le CrawlableLinkButton qui rajoute la propriété NavigateUrl. Les sources du contrôle CrawlableLinkButton se trouve sur aspfr.

Le gridview se transforme alors en

<asp:GridView runat="server" ID="gvProcess" AutoGenerateColumns="false" OnSelectedIndexChanged="gvProcess_SelectedIndexChanged"> <Columns> <asp:TemplateField> <ItemTemplate> <cs:CrawlableLinkButton runat="server" CommandName="Select" Text="Select" NavigateUrl='<%# "temp.aspx?PID=" + Eval("id").ToString() %>' /> </ItemTemplate> </asp:TemplateField> <asp:BoundField DataField="ProcessName" /> <asp:BoundField DataField="VirtualMemorySize" /> </Columns> </asp:GridView>

On voit qu'avec un minimum de code (le CrawLableLinkButton ne fait pas 100 lignes) il est possible de trouver des solutions pour référencer des UpdatePanels, il suffit de se mettre à la place d'un moteur de recherche et analyser le code HTML.

Posted: mardi 16 octobre 2007 12:43 par cyril
Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :

Commentaires

guitoux1 a dit :

"On voit qu'avec un minimum de code (le CrawLableLinkButton ne fait pas 100 lignes) il est possible de trouver des solutions pour référencer des UpdatePanels, il suffit de se mettre à la place d'un moteur de recherche et analyser le code HTML."

... et aussi créer la page temp.aspx qui permettra d'afficher le contenu à référencer :)

# octobre 16, 2007 14:25

cyril a dit :

Dans mon exemple, la page temp était celle qui contient l'UpdatePanel ;-). Il a aussi fallu que je change la méthode CurrentProcess pour prendre en compte le querystring mais 2 lignes de codes à rajouter.

On peut bien sur faire 2 pages différentes et utiliser des UserControls pour ne pas réécrire la partie de détail, ou alors fournir un contenu complétement différent entre l'updatepanel et la page de destination, bref ce n'est pas quelque chose de compliqué ;-)

# octobre 16, 2007 14:52

Aurelien a dit :

Et ca marche, c'est exactement le stratagème que j'ai mis en place sur le site wygwam en 2005 ;-)

Pas d'updatepanel en cause, mais de simples requêtes XmlHttp, à cette époque, on ne parlait pas encore "Atlas" !

Par contre, j'ai un moteur de rendering pour reconstruire les urls que les robots indexent ...

# octobre 17, 2007 00:29
Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- Intégration Yammer et SharePoint Online (Office 365), étape 1 … par Le blog de Patrick [MVP SharePoint] le 06-12-2013, 17:37

- [Dynamics CRM] Ajouter les dossiers de CRM au dossier Favoris d’Outlook par Christine Dubois le 06-10-2013, 15:50

- Visual Studio 2013 par Etienne Margraff le 06-04-2013, 10:26

- Configurer la collation SQL Server pour SharePoint par Blog de Jérémy Jeanson le 06-03-2013, 19:48

- Etendre le Team Web Access de TFS 2012 – Step 1: Création du plugin par Philippe Didiergeorges Aka Philess le 06-03-2013, 07:30

- Livre Blanc : Développer des applications NUI par Fathi Bellahcene le 06-01-2013, 11:35

- [Dynamics CRM 2011] Copier une vue d'entité par Christine Dubois le 05-29-2013, 13:20

- [Conf’SharePoint 2013] Mes présentations… par Le blog de Patrick [MVP SharePoint] le 05-28-2013, 09:04

- [wpdev] Storage bug in MediaLibrary.SavePicture par Kévin Gosse le 05-26-2013, 19:08

- VMMap en mode instrumentation sur système 64bit : attention à la plateforme cible du build .NET par CoqBlog le 05-25-2013, 22:25