Saturday, May 22, 2010

Cross-site and cross-site collection navigation in Sharepoint - part 1

In one of my previous posts I wrote about basic information about navigation architecture in Sharepoint. With this article I continue series of posts about navigation in Sharepoint. Here I will use information described in the previous post, so I recommend to read it before this one.

In real life Sharepoint applications it is common practice to have consistent global navigation (or top navigation bar) across site. It is achievable out of the box with Sharepoint navigation architecture. But it is also common situation when site collection (SPSite) contains multiple sites (SPWeb) and there is a requirement to have consistent navigation when users goes through sites within site collection (it can be navigation items from one of the particular sites, e.g. site collection root site, or it can be navigation items retrieved from custom storage like xml file, database, etc). More complicated case – is when navigation should be preserved within multiple site collections.

This is problem scope which I would like to address in the several posts including this one. I will go from simple to complex and start from most simple scenario: when we have single site collection and several sites under it. First case will assume that we are limited by WSS only. It means neither site collection root web nor its subsites are publishing sites. Publishing sites (sites with publishing infrastructure) have their own navigation API (see previous post) – and it is much more complicated task to preserve cross-publishing sites navigation. I will describe it in next part of navigation-related posts (Update 2010-12-19: see Cross-site and cross-site collection navigation in Sharepoint - part 2: publishing sites).

Sites which were created using one of WSS template initially use one of the following navigation data providers:

  • SPNavigationProvider - provides a base class for Windows SharePoint Services site-map providers that are specialized for SharePoint site navigation;
  • SPSiteMapProvider - provides the SiteMapNode objects that constitute the global content breadcrumb, which represents objects in the site hierarchy above the current site;
  • SPContentMapProvider - provides methods and properties for implementing a site map provider for contents of a Windows SharePoint Services site. This class provides the SiteMapNode objects that constitute the content breadcrumb, where “content” referes to the lists, folders, items, and list forms composing the breadcrumb;
  • SPXmlContentMapProvider - provides methods and properties for implementing a site map provider for contents of a Windows SharePoint Services site. This class provides the SiteMapNode objects that constitute the content breadcrumb, where “content” referes to the lists, folders, items, and list forms composing the breadcrumb.

In order to cover 2 mentioned cases (navigation is preserved from one of the subsites and navigation is preserved globally) we need consider 2 of these navigation providers: SPNavigationProvider  and SPXmlContentMapProvider.

SPNavigationProvider  will help us if need to keep navigation from one particular site. If we will look the code of SPNavigationProvider using reflector we will found that it has public virtual Web property which returns current SPWeb instance:

   1: public class SPNavigationProvider : SiteMapProvider
   2: {
   3:     ...
   4:     protected virtual SPWeb Web
   5:     {
   6:         get
   7:         {
   8:             return SPControl.GetContextWeb(HttpContext.Current);
   9:         }
  10:     }
  11: }

But what is more important is that SPNavigationProvider uses this property as a source for navigation data, i.e. it will return collection of SiteMapNode instances for this web site. So in order to make navigation consistent within all sites we need to implement custom navigation provider by inheriting SPNavigationProvider and override its Web property

   1: public class SingleWebNavigationProvider : SPNavigationProvider
   2: {
   3:     ...
   4:     protected override SPWeb Web
   5:     {
   6:         get
   7:         {
   8:             return SPContext.Current.Site.RootWeb;
   9:         }
  10:     }
  11: }

Here for example purposes site collection root site is used as a source of navigation data, i.e. custom navigation provider SingleWebNavigationProvider will always return navigation items from this SPWeb. In order to use this custom navigation provider in site we need to register it in web.config file of web application:

   1: <siteMap defaultProvider="SPNavigationProvider" enabled="true">
   2:   <providers>
   3:     ...
   4:     <add name="SingleWebNavigationProvider"
   5: type="NamespaceName.SingleWebNavigationProvider, AssemblyName" />
   6:   </providers>
   7: </siteMap>

And then modify master page:

   1: <asp:SiteMapDataSource
   2:   ShowStartingNode="False"
   3:   SiteMapProvider="SingleWebNavigationProvider"
   4:   id="topSiteMap"
   5:   runat="server"/>

After that whenever site you go – navigation data will be used from site collection root web. If you want to preserve navigation across site collections – you need to override Web property so it should return the same site regardless of current site collection (e.g. you can add URL of source web site using custom property of SingleWebNavigationProvider in web.config file and override Initialize(…) method) and modify master pages of all site collections in order to use SingleWebNavigationProvider in them.

Second case – preserving navigation globally can be achieved by using SPXmlContentMapProvider. Specify web application-relative path in its siteMapFile property in web.config:

   1: <siteMap defaultProvider="SPNavigationProvider" enabled="true">
   2:   <providers>
   3:     ...
   4:     <add name="SPXmlContentMapProvider" siteMapFile="_app_bin/layouts.sitemap"
   5: type="Microsoft.SharePoint.Navigation.SPXmlContentMapProvider, Microsoft.SharePoint,
   6: Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
   7:   </providers>
   8: </siteMap>

and modify master page:

   1: <asp:SiteMapDataSource
   2:   ShowStartingNode="true"
   3:   SiteMapProvider="SPXmlContentMapProvider"
   4:   id="topSiteMap"
   5:   runat="server"/>

After that you will have the same static navigation across all sites. If you want to preserve this navigation across site collections you will also need to modify their master pages.

This is all what I wanted to tell about in part 1. In next part I will show how to preserve cross-site and cross-site collection navigation for publishing sites. Update 2010-12-19: see Cross-site and cross-site collection navigation in Sharepoint - part 2: publishing sites.

11 comments:

  1. There's a great solution that based on the same Idea

    You can check out Infowise Enterprise Capacity Solution. It's also based on navigation provider and gives you the ability for a Shared Navigation for SharePoint Site Collections.
    But, Infowise Solution is a little bit better – it caches all the sites with the permissions so the menu becomes security trimmed, it handles all site creation, it stores all the sub sites data on SharePoint hidden lists, it handles the permission inheritance and most important – the installation is simple and straightforward – don’t need to configure web.config file and etc., it’s a simple installer that's doing the job.

    Check it out – http://www.infowisesolutions.com/product.aspx?id=ECS

    ReplyDelete
  2. Eitan,
    one question: does mentioned solution works for publishing sites? You said that it based on the same idea but PortalSiteMapProvider (which is used in publishing sites by default) doesn't allow overriding of current web property (it has CurrentWeb and CurrentSite properties which are not virtual)

    ReplyDelete
  3. Hi Alex

    Thanks for your solution. Do you have part 2 ready yet? I have a web application with many site collections (Publishing sites) that need the same global navigation. I have implemented the custom sitemap but the urls seem to link back to the curuent site and not the urls specified in the sitemap. Can you help me?

    Thanks again,

    Lindsay

    ReplyDelete
  4. Lindsay hi,
    unfortunately part 2 is not ready yet. I can describe you the general idea: you need to implement web service and call this web service in context of your site from where you want to show the navigation. This web service should contain web method which will return list of nodes e.g. in xml form. E.g.:
    http://example1.com <- root site from where navigation should be shown
    http://example2.com/subsite <- some subsite where you want to show navigation from another site http://example1.com

    Your custom site map provider on http://example2.com/subsite should call web service in context of 1st site http://example1.com/_layouts/YorWebService.asmx. This is the only way to retrieve site nodes using publishing site map provider - call it in context of site from where you need to get the navigation data. I hope you got the basic idea

    ReplyDelete
  5. Thanks Alex for Sharing Knowledge but because of my limited knowledge i did not get part where you explained how to create global navigation across site Collection.In my case i have root SiteCollection ARTSCI(http://Server/default.aspx) and then CASIT SiteCollection(http://Server/sites/casit/default.aspx) now i can i create navigation so they can navigate to either of siteCollections.

    Please advise

    Thanks
    Ronak

    ReplyDelete
  6. Ronak hi,
    what site templates are used for the sites on your site collection?

    ReplyDelete
  7. sorry Alex for late Reply
    I am thinking about to use Blank Site Template.we are in planning stage want to make sure can create Cross Site Collection navigation ?

    Thanks
    Ronak

    ReplyDelete
  8. Ronak,
    as far as I remember when you use blank site template then you should choose site template when first access site - and it will create site with select template (or it was only in Sharepoint designer - don't remember now). Anyway if you don't use Publishing sites - you can just create custom navigation provider - inheritor of the SPNavigationProvider and override Web property - you need to return Web site from another site collection.

    ReplyDelete
  9. Thanks Alex will give it try and it will be security trimming right ?
    please advise

    ReplyDelete
  10. as you won't change the logic of security trimming - it should still have it.

    ReplyDelete
  11. I know it's an old thread but still :)
    Regarding ECS, the product from Infowise discussed by Eitan above. It supports both regular and publishing sites, security trimming (with high-performance cache functionality), permission inheritance between site collections, breadcrumbs, trasparent site collection creation and much more. Try it out: http://www.infowisesolutions.com/product.aspx?id=ECS

    ReplyDelete