ASP.NET WebForm Routing with SiteMaps

I’ve updated my ASP.NET WebForm Routing demo with basic SiteMap support.  It’s targeting ASP.NET 3.5 SP1 and expects your WebForm (Page) to implement the IRoutablePage interface (or you can derive from RoutablePage).  If you’re using ASP.NET 4.0 you can omit this dependency (as RequestContext is already available on the Page 🙂 ).

SiteMap raises the SiteMapResolve event whenever its CurrentNode property is read.  This gives you an opportunity to determine the current node based on the route, without requiring a custom SiteMapProvider.  The example below takes the current route URL, removes any route values and looks for a matching SiteMapNode:

private SiteMapNode SiteMap_SiteMapResolve( object sender, SiteMapResolveEventArgs e )
{
    var routable = e.Context.CurrentHandler as IRoutablePage;

    if ( routable != null )
    {
        var rc = routable.Routing.RequestContext;
        var route = rc.RouteData.Route;
        var segments = route.GetVirtualPath( rc, null ).VirtualPath.Split( '/' );
        var path = "~/" + string.Join( "/", segments.Take( segments.Length - rc.RouteData.Values.Count ).ToArray() );

        return SiteMap.Provider.FindSiteMapNodeFromKey( path );
    }

    return null;
}

You create a .sitemap file in the usual way, but put your “routed” URLs in instead:

<?xml version="1.0" encoding="utf-8" ?>
<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
    <siteMapNode url="~/" title="Home" description="Home">
        <siteMapNode url="~/Search" title="Search" description="Search" />
        <siteMapNode url="~/Details" title="Details" description="Details" />
        <siteMapNode url="~/NoMaster" title="No Master" description="No Master">
            <siteMapNode url="~/NoMaster/MySub" title="My Subpage" description="My Subpage"/>
        </siteMapNode>
    </siteMapNode>
</siteMap>

You can use the regular SiteMapPath control to show the current location.  However, you might prefer to render your own.  The sample project includes a couple of helper methods to achieve just that:

/// <summary>
/// Gets SiteMap path for the current request.
/// </summary>
/// <returns></returns>
public string SiteMapPath()
{
    var pages = SiteMap.CurrentNode.For( n => n != null, n => n.ParentNode ).Reverse().Select( n => SiteMapLink( n ) );

    return string.Join( " > ", pages.ToArray() );
}

/// <summary>
/// Gets a SiteMap link.
/// </summary>
/// <param name="node">The node.</param>
/// <returns></returns>
private string SiteMapLink( SiteMapNode node )
{
    var span = string.Format( "<span class=\"siteMapLink\">{0}</span>", node.Title );

    return ( node != SiteMap.CurrentNode )
        ? string.Format( "<a href=\"{0}\">{1}</a>", node.Url, span )
        : span;
}

You can read more about the “For” extension method in my earlier post.

Source code for the sample project is available on CodePlex.  You can try the demo online right here 🙂 .

10 Comments

  1. […] April 25, 2008 · 16 Comments UPDATES: – Updated and simplified sample project. – Updated original post with IIS7 example here. – You can see a sample site running here.  As it’s using IIS6 I needed to add a Wildcard Application Mapping.  Note this passes every request through ASP.NET; you might prefer some alternative options, or use IIS 7 where you get it for free. – Updated sample and overview of using SiteMaps with routing here. […]

    Reply

  2. Superb! I’m going to take a look at this, as the lack of a routing aware sitemap was preventing me from using this in a number of projects,

    Thanks

    Reply

  3. Leigh – Oops sorry! I’ve added the missing file 🙂

    To be honest I’ve not tried it with all route types. If you find it doesn’t work, send me a sample project and I’ll take a look. Chances are it won’t need more than a minor tweak…

    Reply

  4. So I’ve implemented this solution and it works great in FireFox but IE 7 is giving me problems. First something is messed up as stylesheets aren’t showing. Next i am getting a webform_dopostbackwithoptions error due to a dynamic axd file expected (something to do with the login control. Any ideas?

    Reply

Leave a comment