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!
February 21st, 2008 at 21:46
Very nice. May be you could tell how and where to implement this code ?
I am very new to SharePoint, fresh from school, and this was a very good article and solves my problem, but I don’t know what to do with the code.
April 23rd, 2008 at 15:50
Is there a possibility to write a custom provider for the MySite navigation. MySite uses the MySiteMapProvider which is sealed and it ingerits from the SiteMapProvider. I have to add another node to the TopNavigationBar of the MySite and this should happen for all the users whenever they create the site.
Thanks in advance,
Shilpa
April 28th, 2008 at 3:45
Hello.
Thank you for the information.
You just helped me with this article.
April 28th, 2008 at 19:53
Shilpa>
I think so. As the MySiteMapProvider is sealed, you’ll have to mimic it’s behaviour by trial and error, I’m affraid. Also, you maybe will have to change the master page for the my sites, as you will have a custom provider.
Good Luck! Let me know if it works
July 8th, 2008 at 10:37
SPSiteMapProvider and SPContentMapProvider are sealed classes which class did you inherit from?
July 9th, 2008 at 16:08
Excellent! Thank you so much.
July 29th, 2008 at 12:25
I’m with Ketul – what providers did you inherit from? Any chance of seeing all the code?
Also, how does this deal with caching?
July 29th, 2008 at 12:26
[...] stuff about creating a SiteMapProvider on ‘Tomblog’ (but Tom [...]
July 29th, 2008 at 16:18
Please Tombo, can you tell us which class did you inherit from? I have search several times, but find nothing suitable.
July 29th, 2008 at 17:21
I inherited from System.Web.SiteMapProvider. This is a standard .NET class.
About caching: there is none implemented. The caching classes are all sealed or internal. So you’ll have to come up with your own caching procedures. On my project I didn’t implement it yet. However, I don’t have any performance issues. Just make sure you dispose your SPWeb and SPSite objects.
Good Luck!
Tombo
July 30th, 2008 at 11:29
So I tried to implement this, but everytime I added my SiteMapProvider to my web.conf I get an Exception: [HttpException (0x80004005): The DataSourceID of 'TopNavigationMenu' must be the ID of a control of type IHierarchicalDataSource. A control with ID 'topSiteMap' could not be found.]
I added the following to my web.config:
…
July 30th, 2008 at 22:00
Try using a asp:SiteMapDataSource datasource instead of a SharePoint one…
Tombo
January 13th, 2009 at 23:15
morphis: I had the same problem and that link
http://devel.pc-serwis.com/2009/01/custom-navigation-provider-in-sharepoint-gives-shity-errors-part-1/
helped me
March 2nd, 2009 at 18:30
New to SP. Where do I put the class?
April 2nd, 2009 at 11:52
Hi,
i have a requirement to change the user name in the breadcrumb for MySite. Generally the bread crumb displays the site collection admin name, is it possible to change?
thanks in advance
Bhargavi
April 27th, 2009 at 21:44
Thanks for figuring out such clean logic for determining if you’re on a web page or not! I have used this with great success, and just incorporated it into a more detailed post with a Feature receiver class and some more detailed info for folks new to SharePoint development:
http://www.thesug.org/Blogs/ermurray/archive/2009/4/24/CreatingaHybridPublishingSiteMapProviderCustomBreadcrumbNavigationProvider.aspx
August 11th, 2009 at 2:05
worked like a charm! thank you!
November 19th, 2009 at 22:56
,..] tomblog.insomniacminds.com is another nice source on this subject,..]