Recently I get a request to have a consistent top navigation across site collection, in which I need to retrieve the navigation items from a site collection to be used in different site collections (in the same web application). As it is known that SharePoint is using Provider framework to build its navigation, and for Publishing site it is using PortalSiteMapProvider that provides additional caching mechanism. The issue with the provider is that it cannot live cross site collection boundary.
In this post, I would like to share how to build the custom navigation provider utilizing the PortalSiteMapProvider from different site collection (in this post I call it source site collection), I provide the source code at the end of this post. Let’s get started:
- We need to create a custom HttpHandler (ashx) that hosts the source site collection’s PortalSiteMapProvider. The ashx is deployed to layouts directory. This excellent post shows how to build the custom HttpHandler, in fact the source code is based on the post with some modification. Basically the handler will build JSON object tree based on the navigation structure of the source site collection.
- Then create a custom SiteMap provider that calls the ashx created at step 1. The provider will call the handler using WebRequest with the user credential, and deserialize the received JSON into a object structure used by the provider.
- Replace the implementation of OOB site map data source with our own. In v4.master the navigation data sources (SiteMapDataSource) are enclosed in delegate controls, below are the delegate controls in the master page
Navigation Location Delegate Ctl ID Top navigation TopNavigationDataSource Quick launch QuickLaunchDataSource
With this knowledge, we can replace the OOB data source with my own implementation. Below is the definition in my elements.xml to replace the top navigation data source with our own implementation.
<Control Sequence="30" Id="TopNavigationDataSource" ControlClass="System.Web.UI.WebControls.SiteMapDataSource" ControlAssembly="System.Web, Version=220.127.116.11, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> <Property Name="ID">topSiteMap</Property> <Property Name="SiteMapProvider">SymprgNavigationProvider</Property> <Property Name="EnableViewState">false</Property> <Property Name="ShowStartingNode">true</Property> </Control>
You can see that I replaced the top navigation data source implementation to use my custom provider: SymprgNavigationProvider. And also make sure the control sequence number is less than the OOB publishing control defined in Navigation feature (14 hive/TEMPLATE/FEATURES/Navigation /NavigationSiteSettings.xml- the OOB Publishing sequence number is 50). Put this elements.xml to a web scoped feature. By activating the feature we can replace the top navigation.
- The last step is adding the custom navigation handler to the web.config inside siteMap > providers element as shown below. The custom provider (Symprg.NavProvider.NavigationProvider) has two custom attributes:
- sourceUrl: the source site collection url that provides the navigation items
- depth: the depth of the navigation, by default is 1 if not specified.
<siteMap defaultProvider="CurrentNavigation" enabled="true"> <providers> --------------------- <add name="SymprgNavigationProvider" type="Symprg.NavProvider.NavigationProvider, Symprg.NavProvider, Version=18.104.22.168, Culture=neutral, PublicKeyToken=d7699941b48f79bc" sourceUrl="http://aSiteCollection" depth="2"/> </providers> </siteMap>
You can find the source code here.