Using Web.SiteMap with Dynamic URLS (URL Routing)

Armstrongest picture Armstrongest · Nov 15, 2008 · Viewed 14.8k times · Source

I would like to match "approximate" matches in Web.SiteMap

The Web.Sitemap static sitemap provider works well, except for one thing. IT'S STATIC!

So, if I would have to have a sitemapnode for each of the 10,000 articles on my page like so :

  • site.com/articles/1/article-title
  • site.com/articles/2/another-article-title
  • site.com/articles/3/another-article-again
  • ...
  • site.com/articles/9999/the-last-article

Is there some kind of Wildcard mapping I can do with the SiteMap to match Anything under Articles?

Or perhaps in my Webforms Page, is there a way to Manually set the current node?

I've found a "bit" of help on this page when doing this with the ASP.Net MVC Framework, but still looking for a good solution for Webforms.

I think what I'm going to have to do is create a custom SiteMap Provider

Answer

user39603 picture user39603 · Nov 20, 2008

This is in response to the comment above. I can't post the full code, but this is basically how my provider works.

Suppose you have a page article.aspx, and it uses query string parameter "id" to retrieve and display an article title and body. Then this is in Web.sitemap:

<siteMapNode url="/article.aspx" title="(this will be replaced)" param="id" />

Then, you create this class:

public class DynamicSiteMapPath : SiteMapPath
{
  protected override void InitializeItem(SiteMapNodeItem item)
  {
    if (item.ItemType != SiteMapNodeItemType.PathSeparator)
    {
      string url = item.SiteMapNode.Url;
      string param = item.SiteMapNode["param"];

      // get parameter value
      int id = System.Web.HttpContext.Current.Request.QueryString[param];

      // retrieve article from database using id
      <write your own code>

      // override node link
      HyperLink link = new HyperLink();
      link.NavigateUrl = url + "?" + param + "=" + id.ToString();
      link.Text = <the article title from the database>;
      link.ToolTip = <the article title from the database>;
      item.Controls.Add(link);
    }
    else
    {
      // if current node is a separator, initialize as usual
      base.InitializeItem(item);
    }
  }
}

Finally, you use this provider in your code just like you would use the static provider.

<mycontrols:DynamicSiteMapPath ID="dsmpMain" runat="server" />

My class is more complicated than this, but these are the basics. Instead of using a querystring parameter, you could just analyze the friendly url you're using, and use that instead to retrieve the correct content. To minimize the additional db lookups with every request, you can add a caching mechanism to the provider (article title usually won't change often).

Hope this helps.