Click here to Skip to main content
Click here to Skip to main content

Using Multiple Sitemap Files in ASP.NET 2.0

By , 10 Jan 2006
 

Introduction

ASP.NET 2.0 comes with bindable site navigation out of the box in the form of sitemap files. By including a web.sitemap file in the root directory of your website, you can easily bind your navigation control to the sitemap file. But what about placing your sitemap files in app_data (so that they can't be downloaded), or having multiple nav bars and wanting a sitemap file for each of them. This article should give you a good start to overcoming these functionality limitations.

Using the code

The attached project takes the following requirements into consideration. The site has three different areas, a public section for web browsers, a secure section for members, and an administration section. The Secure and Administration sections reside in their own folders so the locations can be secured at a later date. For each section, we have created a master file (located in the masters folder) for consistent look and feel across the section. Each master file will also have its own navigation bar, and will need to bind to its own sitemap file (because the navigation items available in each section will be different). We've placed these sitemap files into the App_Data folder, to prevent them from being downloaded by visitors and spiders.

We now need a way to populate each of these navigation bars with the appropriate sitemap file. This functionality has been abstracted into a user control (UserControls/Menu.ascx), to isolate the logic from the rest of the system.

In the user control, we create a public enum, to represent the different menus available.

public enum SiteMapMenus
{
    Admin, Secure, Public, NotSet
}

I then created a public property to set the menu type at design time.

SiteMapMenus eMenuToLoad = SiteMapMenus.NotSet;
public SiteMapMenus MenuToLoad
{
    get { return eMenuToLoad; }
    set { eMenuToLoad = value; }
}

Now, for the crux of the code. Each menu can accept an XMLDataSource to bind to. The GetMenuDataSource method reads the required sitemap file as an XML file, then creates and returns a data source that can be bound to the control.

XmlDataSource GetMenuDataSource(SiteMapMenus menu, 
                             string serverMapPath)
{
    XmlDataSource objData = new XmlDataSource();
    objData.XPath = "siteMap/siteMapNode";
    switch (menu)
    {
        case SiteMapMenus.Admin:
            objData.DataFile = serverMapPath + @"\App_Data\Admin.sitemap";
            break;
        case SiteMapMenus.Secure:
            objData.DataFile = serverMapPath + @"\App_Data\Secure.sitemap";
            break;
        case SiteMapMenus.Public:
            objData.DataFile = serverMapPath + @"\App_Data\public.sitemap";
            break;
        default:
            break;
    }
    objData.DataBind();
    return objData;
}

We are now almost ready to bind our datasource, but first, as the data source is now XML, and not in the format returned from the sitemap provider, we need to setup our databindings on the menu control itself, as shown below:

<asp:Menu ID="Menu1" runat="server">
    <DataBindings> 
        <asp:MenuItemBinding DataMember="siteMapNode" 
             TextField="title" NavigateUrlField="url"  /> 
    </DataBindings> 
</asp:Menu>

We can now finally bind the source to the control, and this is all fired off in the Page_Load event handler of the User Control.

protected void Page_Load(object sender, EventArgs e)
{
    Menu1.DataSource = GetMenuDataSource(eMenuToLoad, 
                                Server.MapPath("~"));
    Menu1.DataBind();
}

Using our new menu is now as easy as registering the user control on the page, and specifying which menu to display by setting the MenuToLoad property.

<DW:MyMenu ID="MyMenu1" runat="server" MenuToLoad="Secure" />

Something to Note

It is important to point out that for each field specified in your bindings on the menu control, there must be a corresponding item on every node in the sitemap file. For instance, in the attached sitemap files, top level nodes need not have a URL. However, the URL field is still present, and is blank. Removing the URL field from this node will cause a binding exception to be thrown.

I hope you will find this article informative and interesting.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Doug Wilson
Web Developer
South Africa South Africa
Doug is an Applications Integrator for an online gaming company. He has been programming for 9 years, and has been working with the .NET framework since the beginning of 2003, in both VB.NET & C#.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 4membervsanju20-Oct-11 23:03 
yet i didn't view the code, but what i need i got the idea from this view, now i definitely go the code, thank u so much
GeneralMy vote of 5memberjamesCompnet4-Sep-10 5:07 
Well Done , Keep it Up. It was a long time trying to figure out how to load different sitemap data source.
 
Thanks and Regards
GeneralMy vote of 1memberjarajeshwaran22-Oct-09 19:35 
I think this is a very old article. no need to maintain separate sitemap files the asp.net roleprovider already provides this functionality
RantRe: My vote of 1memberTexasMensch27-Jan-10 4:17 
Dont you think that is a little harsh? You acknowledged that this article is old. The criteria should be based upon, was this relevant when it was written. Its not the authors fault if technology advances!
GeneralThanks a lot!memberJules_Joan17-Jan-09 12:28 
I've been looking everywhere for this! Just what I needed! THANK YOU!!!
GeneralCheck this guy's blog - seems easiermemberwgcampbell19-Nov-07 7:03 
http://geekswithblogs.net/dlussier/archive/2007/10/04/115848.aspx[^]
GeneralRe: Check this guy's blog - seems easiermemberJamie Nordmeyer6-Aug-08 12:27 
Very nice. Worked like a charm!
 
Kyosa Jamie Nordmeyer - Taekwondo Yi (2nd) Dan
Portland, Oregon, USA

GeneralMenu does not appearmemberProp Top11-Oct-07 4:06 
For my situation I have variation of the sample code you illustrate.
The menu does not appear at all.
 
Ideas?
 
thanks,
Dave
 
Code:
 
public void BuildMenu(int accessInd)
{
mainMenu.DataSource = GetMenuDataSource(accessInd, Server.MapPath("~"));
mainMenu.Orientation = Orientation.Horizontal;
mainMenu.DataBind();
}
 
XmlDataSource GetMenuDataSource(int accessInd, string serverMapPath)
{
XmlDataSource objData = new XmlDataSource();
objData.XPath = "siteMap/siteMapNode/siteMapNode";
switch (accessInd)
{
case 0:
objData.DataFile = serverMapPath + @"App_Data\Admn.sitemap";
break;
case 1:
objData.DataFile = serverMapPath + @"App_Data\User.sitemap";
break;
default:
break;
}
objData.DataBind();
return objData;
}
 
User.sitemap:
 













Generalitem.Selected DOES NOT WORKmemberGreekShowPony13-Mar-07 20:18 
Hi
 
I really wanted to use this approach, but I can not get the selected state of the item working, and as a result can not use this control until someone finds a way to get it to work.
 
I am using CssFriendly adapters.
QuestionIs this possible??memberjfoju14-Feb-07 17:08 
Hi there,
 
Great article Smile | :)
 
I am implementing this in a slightly different way. I'm pretty new to .NET and to C# so I'm gradually getting my head around the OO side of things. What I'm trying to do is use a single masterpage but based on the user set the menultoload from a session variable using inline C# like this.
MenuToLoad="<%# Session["MenuToLoad"]%>
 
I don't even know if this is a valid technique but I'm getting the following error 'The server tag is not well formed.'
 
If I remove the quotation marks I get a 'System.NullReferenceException: Object reference not set to an instance of an object.' when I the usercontrol code gets to 'TreeView1.DataBind();'
 
I've tried removing the # and get the following 'Parser Error Message: Cannot create an object of type 'UserControls_NavMenu+SiteMapMenus' from its string representation '<%Session["MenuToLoad"]%' for the 'MenuToLoad' property.'
 
Am I far off the mark here?
 
Any suggestions?
 
Thanks
J
QuestionCan we use the same way for implmentation in the SiteMapPath control.membertmiku19-Dec-06 23:16 
Hi,
I want to use multiple SiteMapfiles in the SiteMapPath control is it possible?
GeneralXPath expressionmemberM. Niyazi10-Dec-06 4:08 
when i use "siteMap/siteMapNode" expression, i don't see anything but with "/siteMap/siteMapNode", i see the menu.
 
very helpful article, thanks.
 
mn.yarar

QuestionMenu User Controlmemberkiwimah6-Sep-06 13:40 
This article has been very useful as it has helped solve my problem of different menus for different users.
 
I have altered it slightly to only use one site master and the menu.sitemap is based on the authorisation of the user that is logging in.
 
My problem though is that the 'menu' is not displaying as I would expect.
 
Using the normal menu control and setting the static display levels to '2' and orientation 'horizontal', gives me a drop down list under the higher menu level, of the menu options within that node.
With this menu set as a user control, what I am finding is that the lower level menus are all built into the first level, so they all appear accross the menu bar.
 
Has anyone else either encountered and/or solved this problem?
AnswerRe: Menu User ControlmemberYosefDov3-Oct-06 2:59 
Set
objData.XPath = "siteMap/siteMapNode";
to
objData.XPath = "siteMap/siteMapNode/siteMapNode";
QuestionRe: Menu User Controlmembermanishsawant3-May-07 2:24 
Hi,
 
I am encountering this problem now. Do you have a solution for this. If yes then please email me on manishsawant08@gmail.com.
 
Thanks,
Manish
AnswerRe: Menu User Controlmemberkiwimah3-May-07 17:21 
It's a while ago now. But I think that this is what I used to get it to work. in the UserControl/Menu.aspx
 

<asp:Menu ID="Menu1" runat="server" Orientation="Horizontal"
cssclass="navMenu" maximumdynamicdisplaylevels="1"
skiplinktext="" staticdisplaylevels="2">
<DataBindings>
asp:MenuItemBinding DataMember="siteMapNode" TextField="title"
NavigateUrlField="url"
</DataBindings>
</asp:Menu>

QuestionAlready built in?memberMcGiv8-Mar-06 3:53 
http://msdn2.microsoft.com/en-us/library/ms178426.aspx[^]
AnswerRe: Already built in?memberRed Feet6-Oct-06 0:16 
Thanks McGiv,
 
Your link leads to a good explanation of the built in features for switching between multiple Sitemaps, by defining multiple SiteMapProviders in Web.config
 
I prefer to use built in functionality (if it suits my needs), rather than reinventing the wheel.
 
The built in solution, which worked for me, works like this:
 
Add in the system.web section of the Web.config in the root directory:
 
      <siteMap defaultProvider="XmlSiteMapProvider">
         <providers>
            <add
               name="XmlSiteMapProvider"
               type="System.Web.XmlSiteMapProvider"
               siteMapFile="~/Web.sitemap" />
         <add
               name="MemberSiteMap"
               type="System.Web.XmlSiteMapProvider"
               siteMapFile="~/Member.sitemap" />
         </providers>
      </siteMap>
 
Add in the Page_Load handler of your (Master)page:
 
      If Page.User.Identity.IsAuthenticated Then
            SiteMapDataSource1.SiteMapProvider = "MemberSiteMap" ' for using it with a menu control
            SiteMapPath1.SiteMapProvider = "MemberSiteMap" ' for using it with a sitemap path control
      End If
 

By the way: .sitemap file requests won't be served to visitors and spiders if IIS is setup properly and therefore a .sitemap file can be put in the root or in other public web folders without any risk.
 
I'm sure the article still can be very usefull to understand how you can work around or extend standard .Net functionality.
 
Nice article, Doug!
 
=================
Red Feet
- internet oplossingen -
=================
GeneralRe: Already built in?memberDevinmccloud5-May-07 21:25 
The microsoft .net SDk defines all of this very clearly. Their is no threat to the sitemap files. And doug is right ...that is the properway to do this!
GeneralsecurityTrimmingEnabled Featuremembersoccerchick7-Mar-06 9:40 
This works great! I however ran into a problem. Now within each section of the website I want the menu to only show menu items the user access access to. I setup the Roles and normally with a single siteMap file I use the securitytrimmingEnabled=true attribute in the web.config file.
 
Is there any work around for this?
 
...Carol
GeneralVB.net version of the codememberranbeer2130-Jan-06 23:55 
Can you please please provide the same as well.
QuestionCheck Roles attribute?memberAbishek Bellamkonda23-Jan-06 16:45 
Did you checkout "Roles" attribute in Web.sitemap files? If you set a roles attribute to "Admin, Member" it will show the menu only for admin and members.
 

 
Abi ( Abishek Bellamkonda )
My Blog: http://abibaby.blogspot.com
=(:*
AnswerRe: Check Roles attribute?memberDoug Wilson24-Jan-06 23:33 
I haven't - but thank you - will definetly do so.
 
However, i put this together for use with mutliple navbars in my admin section masterfile. There are 3 navs on the masterfile, and I bind them to 3 different sitemap files.
 
So, in my case, roles would not have helped me out.
 
Doug Wilson

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130617.1 | Last Updated 10 Jan 2006
Article Copyright 2006 by Doug Wilson
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid