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.
| You must Sign In to use this message board. |
|
|
 |
|
 |
I think this is a very old article. no need to maintain separate sitemap files the asp.net roleprovider already provides this functionality
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
 |
|
 |
Very nice. Worked like a charm!
Kyosa Jamie Nordmeyer - Taekwondo Yi (2nd) Dan Portland, Oregon, USA
|
| Sign In·View Thread·PermaLink | 1.00/5 |
|
|
|
 |
|
 |
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:
|
| Sign In·View Thread·PermaLink | 1.00/5 |
|
|
|
 |
|
 |
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.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hi there,
Great article 
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
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
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
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
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?
|
| Sign In·View Thread·PermaLink | 2.00/5 |
|
|
|
 |
|
|
 |
|
 |
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
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
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>
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
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 - =================
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
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!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
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
|
| Sign In·View Thread·PermaLink | 1.00/5 |
|
|
|
 |
|
|
 |
|
|
 |
|
 |
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
|
| Sign In·View Thread·PermaLink | 5.00/5 |
|
|
|
 |
|
|