Posts Tagged ‘SiteMapProvider’

Thursday, October 25th, 2007

SharePoint Branding Issues: Breadcrumb

Navigation can break or make your site, and more specifically, your site’s usability. One of the tools to achieve a good navigation experience is the breadcrumb. In opposite to a menu structure a breadcrumb is quite space saving. And this is, according to MSDN, because it displays a hierarchical path of hyperlinked page names that provides an escape up the hierarchy of pages from the current location.

Basicily, it shows the current node and all its parent nodes. For the sake of completeness, it’s also called an eyebrow. And I’m not making this stuff up.. :p All in all, I’m pretty sure you guys all know the beast. I, for one, find it pretty usefull… as long as it keeps consistency along the way.

Back to SharePoint now. A breadcrumb within ASP.NET is called a SiteMapPath. This is a control which uses an XML sitemap of your site structure to keep track of your every move. It then shows your progress in a nice little breadcrumb. To access the sitemap, we need to use a .NET object called SiteMapProvider. As this is an object in code, we can change the way such a SiteMapProvider works and feed him some custom links programmically in stead of using a XML scheme. This gives a whole lot of flexibility. And because of SharePoint’s inherent dynamic nature, this is why almost all SiteMapProviders within SharePoint are implemented this way.

WSS natively offers a couple of SiteMapProviders (SPNavigationProvider, SPSiteMapProvider, SPContentMapProvider and SPXmlContentMapProvider), each with its specific use within your site. MOSS adds about 10 more. And it’s in MOSS, the troubles begin. Say, you design your site and you have to choose the breadcrumb’s location. Done? Ok.. which SiteMapProvider will you use? The default.masterpage has two (event up to three) breadcrumbs integrated in its design, all with different SiteMapProviders. (I wonder why this design decision was made) The two providers used are:

  • SPContentMapProvider: the default WSS SiteMapProvider which shows nicely all different items and lists
  • CurrentNavSiteMapProviderNoEncode: a provider which parses pages, not as items in a Pages list, but as sections within the site, which is pretty clean.

My requirement was: I want both advantages: items and lists nicely shown and pages cleanly parsed. Unfortunately, the WSS SiteMapProvider does not know pages and the MOSS SiteMapProvider does not parse lists and items. So, I decided to develop my own SiteMapProvider.

A SiteMapProvider consists of two things. A class containing the logic and an entry in the web.config enabling the SiteMapProvider’s use in a masterpage. Let’s first start with the logic.
As this is a MOSS problem only, I created a class inheriting from a MOSS SiteMapProvider: CombinedNavSiteMapProvider. This one will show nice complete breadcrumbs, except of course for lists and items. The SiteMapPath control uses one particular property from the SiteMapProvider: CurrentNode. So this is the one to override. This is the code I came up with:

public override SiteMapNode CurrentNode
{
  get
  {
    SiteMapNode node = base.CurrentNode;
    SPListItem listItem = SPContext.Current.ListItem;
    string url = HttpContext.Current.Request.Url.AbsolutePath;
    bool isItemSelf = listItem != null && url.EndsWith(listItem.Url);
    if (!isItemSelf)
      node = SiteMap.Providers["SPContentMapProvider"].CurrentNode;
    return node;
  }
}

Two things to notice. I check if the url is a page by comparing the requested url with the current item’s url. If they both match, it’s a Page alright. Second thing, to parse with the default WSS provider, one can find the correct provider in the static property Providers from the type SiteMap.
The last piece of the puzzel is the entry in the web.config. This is pretty straight forward. Go to configuration.system.web.siteMap.providers and duplicate the entry of the provider you inherited from. Change the assembly details and you have yourself a working SiteMapProvider.

All in all, this was quite a challenging change to find a solution for and to implement it. But once up, it works like a charm and seems so easy. See you next time!