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.