Using ASP.NET 3.5's ListView and DataPager Controls: Creating an SEO-Friendly Paging InterfaceBy Scott Mitchell
The GridView, FormView, and DetailsView controls all contain built-in paging functionality. By setting a few properties, it's possible to have any of these controls automatically include a paging interface. The ListView, however, does not include built-in paging functionality. Instead, Microsoft decoupled the paging logic from the ListView and moved it into a separate Web control - the DataPager. Paging Through Data with the ListView and DataPager Controls, an earlier article in this series, explored how to use the DataPager to implement a paging interface for the ListView.
By default, the DataPager renders Buttons, LinkButtons, or ImageButtons in the paging interface for the Next, Previous, First, Last, and numeric page number buttons. When clicked, these buttons cause a postback, at which point the appropriate set of records are bound to the ListView. Unfortunately, search engines cannot crawl a site using postbacks; instead, they rely on links they find on your site. Consequently, a search engine will only index the first page of data displayed by a ListView, because it cannot reach the subsequent pages. Also, users cannot bookmark a particular page of data.
The good news is that it is quite easy to modify the DataPager's default behavior. This article shows how to configure the DataPager to use hyperlinks and the querystring to page through a ListView's data (rather than postbacks) to create an SEO-friendly paging interface. Read on to learn more!
The Problem With Postbacks
ASP.NET Web Forms traditionally use postbacks to perform some action. A postback occurs when the user clicks a Button, LinkButton, or ImageButton control, or when they perform some client-side action that has been configured to trigger a postback (such as selecting a different item from a DropDownList control whose
AutoPostBackproperty has been set to True). A postback submits the Web Form, prompting the browser to re-request the same page and to send along the name/value pairs of the
<input>elements within the
<form>. The ASP.NET page is then re-rendered, with the resulting HTML sent back to the browser for and redisplayed.
The postback model works well for many scenarios. One of its shortcomings, however, is that it does not result in an SEO-friendly website. SEO, or Search Engine Optimization, is the practice of improving the quality or quantity of traffic that arrives to a site from search engines. An SEO-friendly website is one whose HTML is structured and laid out in such a way that increases the site's visibility to search engine. Search engines use automated programs to index a website. These "crawlers" typically start by visiting the site's homepage and then burrowing into other web pages on the site that are linked from the homepage. Crawlers will follow links, but they won't submit forms. If you have a page where certain content is only visible after a postback then that data will not get indexed by search engines.
By default, the DataPager renders Buttons, LinkButtons, or ImageButtons for the paging interface. By design, these controls, when clicked, cause a postback. On postback, the DataPager retrieves the requested page of data to display and binds it to the ListView. From the end user's perspective, they click on a page number (or one of the First, Previous, Next, Last buttons) and, voila, the see the appropriate page of data. The problem is that search engine crawlers cannot "click" the buttons in the paging interface and therefore only the first page of results will be indexed. (This SEO-unfriendly behavior is also inherent in the GridView, FormView, and DetailView controls' built-in paging support.)
Fortunately, the DataPager can generate an SEO-friendly paging interface control. As we'll see momentarily, by setting a single property in the DataPager we can instruct it to render hyperlinks in the paging interface and to use a querystring parameter to indicate what page of data to display.
Moving the Page Number to the QueryString
The DataPager includes a
QueryStringFieldproperty that, if set, instructs the DataPager to generate an SEO-friendly paging interface. If the
QueryStringFieldproperty is set, the DataPager renders the paging interface as a series of hyperlinks (instead of rendering the paging interface as a series of Buttons, LinkButtons, or ImageButtons). Specifically, each hyperlink has its
hrefattribute set to the current URL with the page number passed included in a querystring field whose name is the value of the
For example, consider a DataPager control that is configured to show First, Previous, Next, and Last buttons, and that there are five total pages of data being paged through.
Setting the DataPager's
QueryStringField property to "PageNumber" would result in the following paging interface markup when viewing the first page of data:
Because we are viewing the first page of data, the First and Previous links are inactive. Inactive links are rendered as hyperlinks with the
disabled attribute set.
The Next link sends the user to
PageName.aspx?PageNumber=2. Here, the PageNumber querystring parameter is set to 2, but more generally it would be set
currentPageNumber + 1. The Last link sends the user to the fifth and final page of data.
The screen shot below shows the paging interface when rendered as links. The First and Previous links are rendered as text (and not a link) because their
attributes are set.
If the user were to click the Next link they browser would request
PageName.aspx?PageNumber=2. When the page is rendered, the DataPager automatically
checks the querystring for a parameter named the same as its
QueryStringField property (in this case, "PageNumber"). Since this querystring field has a value of 2,
the DataPager will automatically load the second page of data into the ListView. This time, the paging interface will render the following markup:
And that's all there is to it! Creating an SEO-friendly DataPager is a simple as setting its
QueryStringField property to some value. With this change, search
engines can index more than just the first page of data. Additionally, visitors can bookmark a specific page of data, or email the URL to a specific page of data to a friend
Enhancing the Paging User Interface
The paging user interface shown in the screen shot above leaves a lot to be desired. By setting a few properties and adding a sprinkle of CSS we can improve the paging interface dramatically. For starters, let's enhance the paging interface so that instead of just including First, Previous, Next, and Last links, it also includes numeric page numbers. In Paging Through Data with the ListView and DataPager Controls we saw how to specify the DataPager's paging interface via DataPagerFields. The DataPager in the screen shot above contained a single DataPagerField, namely a NextPreviousPagerField pager field. We can add numeric pages as well by using three DataPagerFields:
- A NextPreviousPagerField for the First and Previous options,
- A NumericPagerField for the numeric pages, and
- A NextPreviousPagerField for the Next and Last options.
Note that the first NextPreviousPagerField is configured to that the
FirstPageText property is set to "<<", which will render the text <<
for (rather than First). Also, its
ShowNextPageButton property is set to False so as to hide the Next button. (The Last button is hidden by default.) Similarly,
the second NextPreviousPagerField is configured to suppress the Previous page button and to display the text >> for the Last button.
The screen shot below shows the new paging interface when viewed through a browser.
We can gussy up the appearance with a pinch of CSS. The NextPreviousPagerField and NumericPagerField have properties that allow you to assign a CSS class to the numeric page links,
to the current numeric page link, and to the First, Previous, Next, and Last links. After setting these properties, along with setting the
property to False so as to omit a space between each link in the paging interface, and adding the necessary CSS rules, the resulting paging interface has been transformed to the following:
Note how the current page number is highlighted. In the above screen shot, the user is viewing page 1, which is why the "1" link has a red background and white foreground, whereas the other links in the paging interface have inverted colors (a red foreground on a white background). Also, when hovering your mouse over a paging link its border and text turns black, subtly highlighting it.
The download available at the end of this article has the complete CSS rules and property settings needed to implement the above paging interface.
RenderDisabledButtonsAsLabels - A Tale of an ASP.NET Bug
As we explored earlier in this article, when rendering links the DataPager adds the
disabledattribute to hyperlinks that are not clickable, such as the First and Previous links when viewing the first page of data. Unfortunately, such markup is not XHTML-compliant, as the strict XHTML implementation disallows the
disabledattribute on the
<a>element. The NextPreviousPagerField class has a
RenderDisabledButtonsAsLabelsproperty, which sounds like the perfect solution. Unfortunately, this doesn't work in ASP.NET version 3.5 - when the DataPager's
QueryStringFieldproperty is set the
RenderDisabledButtonsAsLabelsis ignored. The good news is that this bug is fixed in .NET 4.0. (See Using a DataPager with both a
RenderDisabledButtonsAsLabelsfor a more thorough description on the problem in ASP.NET 3.5, as well as a workaround.)
In addition to breaking XHTML compliance, this bug also makes it harder to have the disabled buttons styled differently. For instance, the previous screen shot shows the first page of data, meaning that the First and Previous links are inactive, yet those links appear clickable. Granted, if you hover your mouse over them you'll quickly see that they cannot be clicked, but ideally these disabled links would be displayed differently, using a gray text color, perhaps.
<a> elements with the
disabled attribute that use a specific CSS class (
pagerButton), removes that class, and then adds an
alternate CSS class (
pagerButtonDisabled), which displays the inactive links using a gray text color and removing the border. (While not shown above, I have set the
ButtonCssClass property to
pagerButton, which associates that CSS class with each of the four First, Previous, Next,
and Last links.)
With this in place, the paging interface now "grays out" the inactive paging links, as illustrated in the following screen shot.
By default, the DataPager renders its paging interface using Button, LinkButton, or ImageButton controls. When a visitor clicks one of these paging interface buttons, a postback ensues and the requested page of data is displayed. While this model certainly works, it is does not lead to an SEO-friendly website. With this model, search engines won't index beyond the first page of data. The good news is that the DataPager is designed to render SEO-friendly paging interfaces. By setting the
QueryStringField, the DataPager renders its paging interface as a series of links, passing the requested page number through the querystring.