Click here to Skip to main content
15,881,380 members
Articles / Web Development / ASP.NET

Stop editing 'web.sitemap' - Let unknown pages dynamically inherit from a parent! And more...

Rate me:
Please Sign up or sign in to vote.
4.80/5 (13 votes)
11 Apr 2009CPOL13 min read 274K   1.2K   74   94
Reduce sitemap maintenence and never have another "unlisted" page! Unlisted pages dynamically inherit site map placement from a parent page. Replace repetitive '/default.aspx' mentions with '/' for friendlier URLs. Wildcard query string matching and more...

Introduction

Are you using a 'web.sitemap' file in your web site to produce navigation? Typically, the <asp:SiteMapPath> control is used to generate "bread crumb" navigation similar to this:

Sample Image - ScionSiteMapProvider.jpg

Maintaining the web.sitemap file, however, can be a pain! Every time you add a new page to your site, you must remember to add it to the web.sitemap file. Otherwise, your nice navigation "Home > Products > Widget" suddenly becomes "" - nothing! Not good! I realized forgetting to update the web.sitemap file was a frequent problem and decided I could do better.

What if you didn't need to add every new page to the web.sitemap file? Why couldn't new pages simply inherit from the directory that contained them? For instance, if you added a new page in your /products/ directory say, Widget.aspx, it would automatically become a child of the site map file entry for 'Products', thus yielding "Home > Products > Widget".

Updated! (v.1.1.0.0)
  • If you have used this code before, the class namespace and version have changed. Pay close attention to 'Install the assembly' and 'Modify web.config' below.
  • A Windows installer is now included that will install the assembly into your machine's GAC (Global Assembly Cache) for those not familiar with the GAC and who would like a single-click install.

Enter my ScionSiteMapProvider

'Scion' (pronounced 'cyan') means 'decendant' or 'child'.

ScionSiteMapProvider extends the ASP.NET System.Web.XmlSiteMapProvider class to provide the following features:

  • Inheritance - pages without site map file entries simply become a child of the most logical parent! For instance, if you have site map file entries for your Home and Products directories, new product pages (say, Widgets.aspx and Gadgets.aspx) added to your Products directory automatically become a child of Products, and yield navigation such as "Home > Products > Widgets" without any site map file entries!
  • Default.aspx - get rid of repetitive mentions of default.aspx in your site map file!
  • Wildcard Query String Matching - create one site map file entry that can match any query string.
  • Extensionless URLs - running a site with friendly URLs (no .aspx extensions)? ScionSiteMapProvider can help you!

Additional benefit: Automatically generate web page titles!

Page titles are highly important for search engine placement and display. ScionSiteMapProvider lets you use the title and description information from your site map file to generate unique and appropriate web page titles for every page in your site - even pages that do not have site map file entries!

Automatic recognition of default documents (default.aspx)

Before explaining the main feature of ScionSiteMapProvider which is Inheritance, we need to cover this feature first because it changes the way our site map files look.

ScionSiteMapProvider provides automatic recognition for default documents (default.aspx) eliminating repetitive mentions of /default.aspx in your site map file:

Here is a typical site map file with repetitive default.aspx mentions:

XML
<?xml version="1.0" encoding="utf-8" ?>
<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
    <siteMapNode url="~/default.aspx" title="Tek4.com">
        <siteMapNode url="~/news/default.aspx" title="News" />
        <siteMapNode url="~/dotNET/default.aspx" title=".NET Code" />
    </siteMapNode>
</siteMap>

ScionSiteMapProvider allows you to eliminate all the /default.aspx mentions and simply use / instead:

Here is a site map file without default.aspx mentions:

XML
<?xml version="1.0" encoding="utf-8" ?>
<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
    <siteMapNode url="~/" title="Tek4.com">
        <siteMapNode url="~/news/" title="News" />
        <siteMapNode url="~/dotNET/" title=".NET Code" />
    </siteMapNode>
</siteMap>

Your site map file is now cleaner, and your web site URLs friendlier as well! The <asp:SiteMapPath> control generates navigation links from the site map file. URLs that used to be presented to users as http://www.example.com/default.aspx are now simply http://www.example.com/. How nice!

Because IIS allows any default document file name - or multiple names - you can configure ScionSiteMapProvider to recognize any one or more file names as a default document using the defaultDocuments="" attribute in your web.config file (see the web.config attributes below).

Inheritance

ScionSiteMapProvider provides site mapping for nodes (pages) that do not have a site map file entry by inheriting information from parent nodes! This can greatly reduce site map file maintenance as each specific page does not need a site map file entry!

Examine this simplified web.sitemap file from my web site:

Listing 1
XML
<?xml version="1.0" encoding="utf-8" ?>
<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
    <siteMapNode url="~/default.aspx" title="Tek4.com">
        <siteMapNode url="~/news/default.aspx" title="News" />
        <siteMapNode url="~/dotNET/default.aspx" title=".NET Code" />
    </siteMapNode>
</siteMap>

Using this simple site map file, let's take a look at what navigational bread crumbs would be returned for various URLs:

URLBread crumb
http://tek4.com/Tek4.com
http://tek4.com/news/Tek4.com > News
http://tek4.com/dotNet/Tek4.com > .NET Code

So, what does inheritance do for us? Simply put: it makes life wonderful! How? Consider if I wanted to add a simple 'Contact' page named Contact.aspx. If I were using the built-in XmlSiteMapProvider, I would have to add a line to my site map file for the new page:

Listing 2
XML
<siteMapNode url="~/default.aspx" title="Tek4.com">
    <siteMapNode url="~/Contact.aspx" title="Contact" />
    ...
</siteMapNode>

Now, navigating to the Contact page yields the bread crumb "Tek4.com > Contact".

By why bother? With ScionSiteMapProvider, I don't need to modify my site map file at all! Using the site map file in Listing 1, ScionSiteMapProvider recognizes there is no site map file entry for the Contact.aspx page; thus, it traverses up the directory structure to find the first available parent. In this case, Contact.aspx resides in the root directory so the parent entry is the home page node:

XML
<siteMapNode url="~/default.aspx" title="Tek4.com">

ScionSiteMapProvider thus returns the bread crumb "Tek4.com > Contact" without any need to modify the site map file! Notice that ScionSiteMapProvider recognized the entry with default.aspx as the parent directory entry.

So, using the site map file from Listing 1 with ScionSiteMapProvider, let's take a look at what navigational bread crumbs would be returned for various URLs that aren't in the site map!

URLBread crumb
http://tek4.com/Contact.aspxTek4.com > Contact
http://tek4.com/news/Headlines.aspxTek4.com > News > Headlines
http://tek4.com/news/2007/Jan.aspxTek4.com > News > 2007 > Jan
http://tek4.com/dotNet/ScionSiteMapProviderTek4.com > .NET Code > ScionSiteMapProvider

"Wildcard" query string matching

Provides new "wildcard" query string variable matching. The standard XmlSiteMapProvider class can match a particular query string (i.e., http://www.example.com/products/showproduct.aspx?id=1), but what if you have product IDs 1 through 100? That would require one hundred site map file entries! ScionSiteMapProvider has wildcard matching that matches any query string, so one site map entry can handle all of your product IDs!

Use friendly URLs without the .aspx extension

Ability to strip file extensions (.aspx and others) for web sites using URLs without extensions. If your web server is IIS 6.0, a product called PageXchanger (see http://www.pagexchanger.com/) eliminates the ".aspx" extensions. I wrote an HTTPModule that works with IIS 7.0 for removing the ".aspx" from all of my URLs. This makes for friendlier URLs ("/contact" instead of "/contact.aspx"), and hides that I am using ASP.NET on my server. If I switch to PHP next year, I won't have to worry about my URLs changing. ScionSiteMapProvider allows you to work without extensions on your URLs if you are so equipped.

Using the code

Install the assembly

Download or compile the assembly Tek4.Web.ScionSiteMapProvider.dll. Note that the pre-compiled assembly I have provided for download is already strong-named and signed with my security key as follows:

"Tek4.Web.ScionSiteMapProvider, Version=1.1.0.0, 
  Culture=neutral, PublicKeyToken=26c804c56bafc725"

Note: If you re-compile the source, your assembly will have different naming, which will affect the web.config file below.

The simplest installation is to copy the assembly to your web site's /bin directory.

GAC installation

In addition to the pre-compiled .dll, I have also provided an .msi installer that installs the Tek4.Web.ScionSiteMapProvider assembly into the machine's Global Assembly Cache (GAC). If you plan on using ScionSiteMapProvider for more than one web site on the same server, installation into the GAC means only a single copy is needed.

You need Administrator privilege to install assemblies into the GAC and run .MSI files, so hosted web customers won't have this option. Also, assemblies must be strong-named in order to be installed in the GAC. The assembly I supply is already strong-named (see above).

Modify web.config

In the <system.web> section of your web.config file, you need to specify ScionSiteMapProvider as a site map provider. If you are currently utilizing the ASP.NET XmlSiteMapProvider, your web.config file will contain a section similar to this:

XML
<system.web>
...
  <siteMap>
    <providers>
      <add siteMapFile="web.sitemap" name="AspNetXmlSiteMapProvider"
       type="System.Web.XmlSiteMapProvider, System.Web, Version=2.0.0.0,
       Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
      </providers>
  </siteMap>
...
</system.web>

In your web.config file, substitute or add the section below:

XML
<system.web>
...
  <siteMap defaultProvider="Tek4ScionSiteMapProvider">
    <providers>
      <add siteMapFile="web.sitemap" name="Tek4ScionSiteMapProvider"
       type="Tek4.Web.ScionSiteMapProvider,Tek4.Web.ScionSiteMapProvider,
       Version=1.1.0.0, Culture=neutral, PublicKeyToken=26c804c56bafc725" />
    </providers>
  </siteMap>
...
</system.web>

web.config attributes

ScionSiteMapProvider recognizes many attributes in the web.config file that can be used to configure specific operations. A full listing follows, also indicating the default value of each possible attribute:

defaultDocuments="default.aspx"

Specifies file names that are recognized as default documents for a directory. You may specify more than one file name by using the '|' character as a delimiter; for example: defaultDocuments="default.aspx|index.aspx".

description="Extends XmlSiteMapProvider to provide mapping for URLs that do not have a sitemap file entry by inheriting information from a parent entry."

Overridden from XmlSiteMapProvider. Provides a brief, friendly description of ScionSiteMapProvider suitable for display in administrative tools or other user interfaces (UIs). This attribute might be accessed if you were to inherit XmlSiteMapProvider in a programming project, but you need not be concerned with it otherwise.

inherit="true"

Specifies whether site map node inheritance is enabled. Setting this attribute to "false" disables inheritance.

name="Tek4ScionSiteMapProvider"

Inherited from XmlSiteMapProvider. Specifies a friendly name used to refer to the provider during configuration.

scionTitle="Path"

Specifies the naming scheme to use for scion node (inherited node) titles. Can be one of:

  • Path - full sub-path from URL
  • First - first (highest) level name from URL only
  • Last - last (lowest) level name from URL only

For example, let's assume you have a site map entry for "Home > News" and an unlisted page is requested at /News/2007/Jan/13.aspx. With the default scionTitle setting of "Path", the resulting node's title will be "2007 > Jan > 13". Specifically, each hierarchal name in the path (directories and file name) is concatenated with the titleSeparator string (see below) to create the scion node's title. When displayed with the <asp:SiteMapPath> control, the user will see "Home > News > 2007 > Jan > 13".

If scionTitle is set to "First", only the first hierarchal name in the path is used, and the resulting title will be "2007". Using "Last", only the file name portion is used and the scion node's title will be "13".

siteMapFile

Inherited from XmlSiteMapProvider. Specifies the file name of the site map file.

stripFileExt="false"

Specifies whether or not URL file extensions are stripped. When set to "true", XmlSiteMapProvider strips file extensions (such as ".aspx") before looking for matches in the site map file. You should only enable this feature if you are using software such as PageXchanger from Port80Software (see http://www.pagexchanger.com/) that allows you to operate your web site without file extensions on your URLs.

If your web site is hosted via IIS 7.0: I wrote an HTTPModule that gets rid of the nasty ".aspx" extensions in place of using PageXchanger, which is for IIS 5 and 6. Contact me below if you are interested.

titleSeparator=" > "

Specifies the string used as a separator between path levels when the scionTitle attribute is set to "Path". For example, if you have a site map entry for "Home > News" and an unlisted page is requested at /News/2007/Jan/13.aspx the resulting node's title will be "2007 > Jan > 13". When displayed with the <asp:SiteMapPath> control, the user will see "Home > News > 2007 > Jan > 13".

Create/Modify your site map file

If you have an existing site map file, you must remove all mentions of default documents (usually default.aspx) in order for the inheritance feature to work! Change site map entries such as:

XML
<siteMapNode url="~/default.aspx" title="Home">

The modified site map entry should be:

XML
<siteMapNode url="~/" title="Home">

Other file names that you have configured to be default documents in IIS (e.g., index.aspx, etc.) should not be specified in your site map file. You must configure ScionSiteMapProvider to recognize additional or alternative default document file names using the defaultDocuments attribute in your web.config file.

You can name your site map file anything you like. The siteMapFile parameter in the web.config file specifies the name of your site map file; the generic name, web.sitemap, is common.

Your site map file depends on your web site, of course. But, the most minimal site map file should at least contain a node for the root - or home - directory. Doing this ensures that every page in your site will always be a child of "Home":

Minimal web.sitemap file:
XML
<?xml version="1.0" encoding="utf-8" ?>
<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
    <siteMapNode url="~/" title="Home">
    </siteMapNode>
</siteMap>

Showing navigation on your pages

There are many useful ways to consume site map information, but the easiest is to display the familiar "bread crumb" navigation on your web page (typically at the top under the header):

Sample Image - ScionSiteMapProvider.jpg

Just add the ASP.NET SiteMapPath control to your page's code:

XML
<asp:SiteMapPath id="SiteMapPath" runat="server" />

Automatic page titles from site map descriptions!

One of the most useful applications for site map file information is to generate automatic titles for all of your web pages. Search engines like Google prioritize page titles very highly and display search results with the page title highlighted. Therefore, having all your web pages titled "My Web Site" isn't helping your search engine rankings!

How to generate page titles from your site map file

First, your site should use .master pages (or some other method) so that the HTML <head> and <title> tags are in one place instead of replicated on each individual page.

To programmatically access and modify the page title, you must use the ASP.NET header control: <head runat="server" />. In my master page, I also specify a "default" title that is used as a prefix for all web page titles:

XML
<head runat="server">
  <title>Tek4 Innovations</title>
  ...
</head>

In the same master page, I override the Page_Load method to append site map information to the page title - with a few twists:

C#
<script runat="server">
  void Page_Load(Object sender, EventArgs e) {
    // Set page title based upon SiteMap Description or Title
    SiteMapNode currentNode = SiteMap.CurrentNode;
    if (currentNode != null) {
      String subTitle = currentNode.Description;
      if (subTitle.Length == 0) subTitle = currentNode.Title;
      if (subTitle.Length !=0 && subTitle != "Home") 
          Page.Title += "\u2014" + Server.HtmlEncode(subTitle);
    }
  }
</script>

The function of the above code is as follows:

  1. If SiteMap.CurrentNode is null, then leave the default page title alone.
  2. Append currentNode.Description to the page title. If empty, append currentNode.Title instead. If both are empty, then leave the default page title alone.
  3. The appended text is passed through the Server.HtmlEncode() method to properly encode any HTML entities (such as '&').
  4. A specific check for the "Home" page leaves the default page title alone to prevent appending "Home".
  5. The Unicode character \u2014 is the em-dash or '—', and I use it to separate my default title from the appended text.

Troubleshooting

If you have problems, it would be first nice to confirm that ScionSiteMapProvider is actually your application's site map provider. Place this code somewhere in one of your web pages:

ASP.NET
<%=SiteMap.Provider.GetType()%>

The code will return the site map provider's type:

Tek4.Web.ScionSiteMapProvider

If you are, in fact, utilizing ScionSiteMapProvider, chances are you did not modify your site map file to remove mentions of default.aspx (see Using the code above).

History

  • 2007-Jan-13: v.1.0.0.0 - Original post.
  • 2007-Jan-17: v.1.0.0.1 - Minor bug fix.
  • 2009-Apr-05: v.1.0.0.3 - Allows partially trusted callers ('Medium' trust level).
  • 2009-Apr-11: v.1.1.0.0 - Changed namespace to Tek4.Web; also created a .MSI GAC installer.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
Kevin Rice is a firefighter for a major Southern California fire department. When not working, he enjoys web programming, administration, riding dirt-bikes (Visit SLORider.com) or building anything electronic.

Comments and Discussions

 
GeneralRe: Passing Query string and setting Web.cofig attributes Pin
shinup793-Aug-08 20:50
shinup793-Aug-08 20:50 
GeneralRe: Passing Query string and setting Web.cofig attributes Pin
kriceslo19-Aug-08 10:59
kriceslo19-Aug-08 10:59 
QuestionSupport for Resource file? Pin
gwheeloc14-Apr-08 9:17
gwheeloc14-Apr-08 9:17 
GeneralRe: Support for Resource file? Pin
kriceslo14-Apr-08 9:27
kriceslo14-Apr-08 9:27 
GeneralRe: Support for Resource file? Pin
gwheeloc14-Apr-08 10:03
gwheeloc14-Apr-08 10:03 
GeneralRe: Support for Resource file? Pin
gwheeloc14-Apr-08 10:09
gwheeloc14-Apr-08 10:09 
GeneralRe: Support for Resource file? Pin
gwheeloc14-Apr-08 10:29
gwheeloc14-Apr-08 10:29 
GeneralRe: Support for Resource file? Pin
kriceslo14-Apr-08 10:35
kriceslo14-Apr-08 10:35 
GeneralRe: Support for Resource file? Pin
kriceslo14-Apr-08 10:34
kriceslo14-Apr-08 10:34 
GeneralRe: Support for Resource file? Pin
kriceslo14-Apr-08 10:32
kriceslo14-Apr-08 10:32 
GeneralRe: Support for Resource file? Pin
gwheeloc14-Apr-08 10:47
gwheeloc14-Apr-08 10:47 
AnswerRe: Support for Resource file? Pin
kriceslo14-Apr-08 11:00
kriceslo14-Apr-08 11:00 
QuestionProblem with Query String Pin
kurtstricker12-Apr-08 5:21
kurtstricker12-Apr-08 5:21 
GeneralRe: Problem with Query String Pin
kriceslo12-Apr-08 7:27
kriceslo12-Apr-08 7:27 
GeneralRe: Problem with Query String [modified] Pin
kurtstricker12-Apr-08 10:03
kurtstricker12-Apr-08 10:03 
GeneralRe: Problem with Query String Pin
kriceslo12-Apr-08 11:25
kriceslo12-Apr-08 11:25 
GeneralRe: Problem with Query String Pin
kurtstricker12-Apr-08 12:18
kurtstricker12-Apr-08 12:18 
GeneralRe: Problem with Query String Pin
kriceslo12-Apr-08 16:30
kriceslo12-Apr-08 16:30 
GeneralRe: Problem with Query String Pin
kurtstricker12-Apr-08 17:39
kurtstricker12-Apr-08 17:39 
GeneralRe: Problem with Query String Pin
kriceslo12-Apr-08 18:06
kriceslo12-Apr-08 18:06 
GeneralRe: Problem with Query String Pin
kurtstricker14-Apr-08 16:44
kurtstricker14-Apr-08 16:44 
GeneralRe: Problem with Query String Pin
kriceslo14-Apr-08 16:47
kriceslo14-Apr-08 16:47 
Generalduplicate names Pin
richseebs16-Jan-08 6:50
richseebs16-Jan-08 6:50 
GeneralRe: duplicate names Pin
kriceslo16-Jan-08 7:56
kriceslo16-Jan-08 7:56 
GeneralRe: duplicate names Pin
richseebs22-Jan-08 3:10
richseebs22-Jan-08 3:10 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.