ManuelAbadia.com
PagerDataSource samples
Samples



Product Information

Search Engine Optimization (Part 2)

The sample "Search Engine Optimization (1)" showed how to use the PagerDataSource control to obtain a navigable structure that is more search engine friendly. However, usually the spiders limit the number of pages to index that use dynamic parameters. For example, this is an excerpt of the Google FAQ:

"We're able to index dynamically generated pages. However, because our web crawler could overwhelm and crash sites that serve dynamic content, we limit the number of dynamic pages we index. In addition, our crawlers may suspect that a URL with many dynamic parameters might be the same page as another URL with different parameters. For that reason, we recommend using fewer parameters if possible. Typically, URLs with 1-2 parameters are more easily crawlable than those with many parameters."

There are some spiders that do not index any page with dynamic parameters so in order to further optimize the search engine positioning we can use an URL rewriter to transforms URLs like http://www.myserver.com/products.aspx?idCat=2idProd=34&Page=5 to URLs like http://www.myserver.com/idCat/2/idProd/34/Page/5/products.aspx where the parameters are part of the directory structure. There are a lot of URL rewriters on the net, some work at web server level, some are coded as ASP.NET HTTP Handlers or HTTP Modules, or even as a Virtual Path Provider. For the example we are going to use a free URL rewriter available at:

http://www.urlrewriting.net/

The PagerDataSource has two virtual methods that could be overridden in order to add support for URL rewriting. The methods are:

  • protected vritual bool TryGetCurrentPage(out int newPage);
  • protected virtual string GenerateUrl(int destinationPage);

The TryGetCurrenPage method is used to check if the current page has changed. The default implementation searchs for a query string parameter named as the PageKey. If the key is found, the method returns true and sets the newPage output parameter as the value for the PageKey.  The GenerateUrl returns a string with the URL to navigate when the user clicks a navigation link in the PagerDataSource when the control is in "QueryStringMode". The default implementation appends the current page to the query string under a parameter called PageKey.

In order to use the UrlRewriting module pointed above, we only need to inherit from PagerDataSource and override the GenerateUrl method in order to pass the parameters in the directory structure. The full source code is at the bottom of page. The URL rewriting module has been configured to rewrite URLs like this:

 

<urlrewritingnet

    rewriteOnlyVirtualUrls="true" 

    contextItemsPrefix="QueryString"

    xmlns="http://www.urlrewriting.net/schemas/config/2006/07" >

    <rewrites>

      <add name="RewritePages" virtualUrl="^~/(.*?)/(.*?)/(.*).aspx"

          rewriteUrlParameter="ExcludeFromClientQueryString"

          destinationUrl="~/$3.aspx?$1=$2"

          ignoreCase="true"/>

    </rewrites>

  </urlrewritingnet>


The source code for this page is shown after the live sample.


Product List

<<<1|2|3|4|5|6|7|8>>>
1
Product 1
Full description for product number 1
2.00 $
2
Product 2
Full description for product number 2
4.00 $
3
Product 3
Full description for product number 3
6.00 $
4
Product 4
Full description for product number 4
8.00 $
5
Product 5
Full description for product number 5
10.00 $
6
Product 6
Full description for product number 6
12.00 $
7
Product 7
Full description for product number 7
14.00 $
8
Product 8
Full description for product number 8
16.00 $
9
Product 9
Full description for product number 9
18.00 $
10
Product 10
Full description for product number 10
20.00 $
11
Product 11
Full description for product number 11
22.00 $
12
Product 12
Full description for product number 12
24.00 $
13
Product 13
Full description for product number 13
26.00 $
14
Product 14
Full description for product number 14
28.00 $
<<<1|2|3|4|5|6|7|8>>>

Sample source code

The ASPX file for this sample is:.


<%@ Page Language="C#" MasterPageFile="~/DefaultMaster.master" AutoEventWireup="true" CodeFile="SearchEngineOptimization2.aspx.cs" Inherits="SearchEngineOptimization2" Title="Search Engine Optimization" %>


<%
@ Register Assembly="PagerModified" Namespace="Manu.Web.UI.WebControls" 
    TagPrefix
="manuSamples" %>

 

<asp:Content ID="Content1" ContentPlaceHolderID="Content" Runat="Server">

    <h2>Product List</h2>

 

    <manuSamples:UrlRewritingPager ID="PagerDataSource1" runat="server"

        DataSourceID="ObjectDataSource1" PageSize="14" Mode="QueryStringRedirect">

    </manuSamples:UrlRewritingPager>

 

    <asp:DataList ID="DataList1" runat="server"

        DataKeyField="id" DataSourceID="PagerDataSource1"

        RepeatColumns="7" RepeatDirection="Horizontal" Width="100%">

        <ItemTemplate>

            <table>

                <tr>

                    <td align="center">

                        <asp:Label ID="idLabel" runat="server"

                        Text='<%# Eval("id") %>'></asp:Label>

                    </td>

                </tr>

                <tr>

                    <td align="center">

                        <b><asp:Label ID="nameLabel" runat="server"

                        Text='<%# Eval("name") %>'></asp:Label></b>

                    </td>

                </tr>

                <tr>

                    <td align="center">

                        <asp:Label ID="descriptionLabel" runat="server"

                        Text='<%# Eval("description") %>'></asp:Label>

                    </td>

                </tr>

                <tr>

                    <td align="center">

                        <asp:Label ID="priceLabel" runat="server"

                        Text='<%# Eval("price", "{0:#0.00}") %>'>

                        </asp:Label> $

                    </td>

                </tr>

            </table>

        </ItemTemplate>

        <ItemStyle BackColor="White" ForeColor="#436799" />

    </asp:DataList>

 

    <manuSamples:UrlRewritingPager ID="PagerDataSource2" runat="server"

        DataSourceID="PagerDataSource1" PageSize="14" Mode="QueryStringRedirect">

    </manuSamples:UrlRewritingPager>

 

    <asp:ObjectDataSource ID="ObjectDataSource1" runat="server" TypeName="ProductsDAL"

        SelectMethod="GetPagedData" SelectCountMethod="CountAll" EnablePaging="True"

        MaximumRowsParameterName="maxRows" StartRowIndexParameterName="startIndex">

    </asp:ObjectDataSource>

</asp:Content>


The code-behind file (ASPX.CS) is:


using System;

 

public partial class SearchEngineOptimization2 : System.Web.UI.Page

{

    protected void Page_Load(object sender, EventArgs e)

    {

    }

}


The code to generate URLs for the rewriting module is:


using System;

using System.Text;

using Manu.Web.UI.WebControls;

using UrlRewritingNet.Web;

 

namespace Manu.Web.UI.WebControls

{

    public class UrlRewritingPager : PagerDataSource

    {

            public override string GenerateUrl(int destinationPage)

        {

            // in design mode, delegate to the parent class

            if (DesignMode) {

                return base.GenerateUrl(destinationPage);

            }

 

            string urlPath, page;

 

            // get the current URL path and the current page

            GetUrl(out urlPath, out page);

 

            // creates a string builder to build the fake directory structure

            StringBuilder sb = new StringBuilder();

            sb.Append(urlPath);

            foreach (string key in Context.Request.QueryString.Keys) {

                // add the parameter if it's not the paging parameter

                if (String.Compare(key, PageKey) != 0) {

                    sb.Append(key);

                    sb.Append('/');

                    sb.Append(Context.Request.QueryString[key]);

                    sb.Append('/');

                }

            }

 

            // adds the paging parameter

            sb.Append(PageKey);

            sb.Append('/');

            sb.Append(destinationPage);

            sb.Append('/');

 

            // adds the page

            sb.Append(page);

 

            return sb.ToString();

 

        }

 

        public void GetUrl(out string urlPath, out string page)

        {

            // gets the URL of the request

            string url = Context.Request.Url.AbsoluteUri;

 

            // if the path has been rewriten, get the real path

            if (Context.Items[UrlRewriteModule.PhysicalPath] != null) {

                url = (string)Context.Items[UrlRewriteModule.PhysicalPath];

            }

 

            // deletes the query string from the url

            int queryCharIndex = url.IndexOf('?');

            if (queryCharIndex != -1) {

                url = url.Substring(0, queryCharIndex);

            }

 

            // extracts the page from the url

            int lastSlash = url.LastIndexOf('/');

            page = url.Substring(lastSlash + 1);

 

            // delete the page from the url

            urlPath = url.Substring(0, lastSlash + 1);

        }

    }

}