This article replaces my earlier article about MCMS Navigation Providers which I have written while ASP.NET 2.0 was in Beta 2. After Beta 2 a couple of things have changed which prevent the earlier code from working properly with the final version of ASP.NET 2.0.
ASP.NET 2.0 provides new concepts to implement site navigation based on new server controls and the Site Map Provider concept. The controls and the provider work together and allow the implementation of a very flexible and scalable solution for site navigation.
The SiteMapProvider represents the data layer while the controls represent the presentation layer of the navigation. The SiteMapProvider provides information about the different elements in the navigation structure through SiteMapNode objects which need to be populated by the provider with the relevant information from the underlaying datasource. SiteMapNode allows to provide a unique Key, a Title, a URL and a Description. In addition during creation of the SiteMapNode a unique key for the Node has to be provided.
For MCMS the datasource is usually the channel structure. A SiteMapProvider for MCMS would have to read the information about the requested channel item from the MCMS repository and has to return a SiteMapNode object that contains the relevant information about this channel item:
ChannelItem ci = ...; SiteMapNode smn = new SiteMapNode(this, ci.Guid); // we use the GUID as the Key for the Node. smn.Url = ci.Url; smn.Title = ci.DisplayName; smn.Description = ci.Description;
The code above shows how to create a SiteMapNode based on a MCMS channel item. Here we are using the GUID of the channel item as unique key, the Url property for the Navigation URL. In addition we copy the Description and DisplayName properties to the Description and Title properties of the SiteMapNode object. Instead of the GUID we could also have used the Path property but as this property will later be used to retrieve the associated channel item from the repository it's better to use the GUID as a Searches.GetByGuid method call is quicker than a Searches.GetByPath method call.
A custom SiteMapProvider for MCMS should implement at least the following methods:
A SiteMapProvider can implement some more methods but only the methods above are really required for the navigation controls shipped with ASP.NET 2.0 to work correct with MCMS 2002.
A very basic SiteMapProvider for MCMS which can be used by the ASP.NET 2.0 navigation controls would look like the following:
To use the above SiteMapProvider you need to add the code above to a C# class library project and compile it into a DLL. Then add the provider to your ASP.NET 2.0 template project web.config file as follows:
<system.web> <siteMap defaultProvider="MCMSSiteMapProvider" enabled="true"> <providers> <add name="MCMSSiteMapProvider" type="StefanG.SiteMapProviders.MCMSSiteMapProvider, MCMSSiteMapProvider"/> </providers> </siteMap> </system.web>
That's all! Now the ASP.NET 2.0 navigation controls can use this SiteMapProvider. No further coding is required! It is possible to add multiple different SiteMapProviders to your site. This makes sense if your have different kind of controls where some items should be shown or hidden based on your business needs. E.g. one provider should only return channels with a specific custom property. To achieve this implement a second provider that checks for these properties in the GetChildNode method and bind this SiteMapProvider explicitly to your control.
ASP.NET 2.0 ships with three new controls that can be used for site navigation:
The SiteMapPath control - which behaves like the Woodgrove Breadcrumb control - requires a SiteMapProvider and cannot be used without it. Just drag a SiteMapPath control on your template or channel rendering script and your MCMS bread crumb is ready - if you configured the SiteMapProvider above in your web.config.
To use the Menu and the TreeView control with our SiteMapProvider you first need to drag a SiteMapDataSource object to your template or channel rendering script. Either explicitly configure the SiteMapProvider to be used using the SiteMapProvider property or let this property blank and the configured default provider will be used. Then drop the TreeView or Menu control to your template or channel rendering script and configure the SiteMapDataSource you dropped earlier as the datasource to use for the control.
One hint for the TreeView control: you should ensure that child nodes are populated on demand - otherwise all nodes are retrieved when the page is first requested which can slow down your MCMS site significantly if your provider enumerates the whole repository. To do this you need to set the PopulateOnDemand property in the TreeNode Databinding properties to true.
In the next article I will discuss an additional problem with the TreeView control which only occurs in the final version of ASP.NET 2.0 and not with the Beta-2 bits and which prevents the TreeView control from working correct on a MCMS template or channel rendering script.
Thanks for this. Works like a charm. One thing you should know is that "FindSiteMapNode(string GUID)" still has some issues when you set the "StartingNodeUrl" property of the SiteMapDataSource. Entering an url obviously doesn't work, but neither does a GUID because VS.NET 2005 thinks it's a relative path and prepends the parent path. So I ended up writing a little GUID or Url detector anyway.
thanks for the info! I haven't used this property till now - that's why I did not yet run into this issue.
I adjusted the article now to work correct in this situation. Please have a look if the issue is resolved now.
Nice one. I found one other small bug. I'm consuming Sitemap data using my own controls, so this might not happen with the standard controls.
When creating a new page based on a template that uses SiteMap controls, I found that CMS fails to find the node passed to "GetParentNode" (Searches.GetByGuid(node.Key) returns null).
There is no check on this so the following "ci.parent" will throw an exception. Fixed it with a simple wrapper.
Also you might want to make "GetSiteMapNodeFromChannelItem" virtual. I found it much easier to override this method in my extension then to target the other methods.
I wrote my own extension to this class to deal with my site. Basically it folds channels that contain only a single posting into one node, so the channel looks like a posting to all sitemap controls. This is very useful when you want to apply specific security to only one posting (which you can't without a seperate channel) without stuffing up the layout on your sitemap controls.
I just updated this SiteMapProvider. The GetParentNode contained a bug which prevented it from working correct for the SiteMapPath control when a new Posting was created.
Edward, thanks for this hint!
FYI i am trying to do the nav on the master page and i do have the directives on the top. Everything else is working great.
this sounds interesting! Please send me a mail to webmasterATstefan-gossner.de to let us follow up offline. (Please replace AT with @)
Thanks for the info on that control :) It works great :)
However, I've discovered that there seems to be a problem utilizing the menu control (any site map provider) when using CMS and Master Pages. I haven't figured out why, but I thought it might be worth noting. I think that's what Willie might be referencing (if he has Master Pages).
I should state that I seem to be having a problem with the Menu control and Master Pages. It might be a fluke :)
I have found a possible reason for the problems with the menu control. It does not work correct if the following tag is included in the web.config:
Removing this tag resolves the issue.
This affects as well normal ASP.NET webform projects and MCMS template projects.
That fixed it exactly. Thank you :)
This can be used with ASP 2.0 but I have ASP1.1 with VS 2003. Is there a control to create the sitemap for ASP 1.1??
ASP.NET 1.1 does not support site maps and does not ship with any controls that use site maps.
You would need to reinvent the wheel.
I would suggest to upgrade your site to ASP.NET 2.0 and VS.NET 2005.
Is there a way for me to start the root node of the site map on a different level? I am able to make the sitemap, its just that I want the root channel to start on a different level..