ASP.NET MVC and Menu Trimming
July 13, 2010 Leave a comment
One of the nice features with ASP.NET is menu trimming pretty much out of the box. You need to:
Create a SiteMap:
<?xml version="1.0" encoding="utf-8" ?>
<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
<siteMapNode url="" title="" description="">
<siteMapNode url="/Public" title="Public" description="">
<siteMapNode url="/Public/PublicContent1" title="Public Content #1" description="" />
<siteMapNode url="/Public/PublicContent2" title="Public Content #2" description="" />
</siteMapNode>
<siteMapNode url="/Private" title="Private" description="">
<siteMapNode url="/Private/PrivateContent1" title="Private Content #1" description="" />
<siteMapNode url="/Private/PrivateContent2" title="Private Content #2" description="" />
</siteMapNode>
</siteMapNode>
</siteMap>
Add the sitemap to your web.config:
<siteMap defaultProvider="DefaultSiteMapProvider" enabled="true">
<providers>
<add name="DefaultSiteMapProvider" type="System.Web.XmlSiteMapProvider" siteMapFile="Web.sitemap"
securityTrimmingEnabled="true" />
</providers>
</siteMap>
Add some roles to your web.config that protect certain areas
<location path="~/Private">
<system.web>
<authorization>
<deny users="*"/>
<allow roles="admin"/>
</authorization>
</system.web>
</location>
Add a SiteMapDataProvider and a menu to your form that uses your SiteMapDataProvider:
<div class="clear hideSkiplink">
<asp:SiteMapDataSource ID="siteMapDataSource" runat ="server" ShowStartingNode="false" />
<asp:Menu ID="NavigationMenu" runat="server" CssClass="menu" EnableViewState="false"
IncludeStyleBlock="false" Orientation="Horizontal" DataSourceID="siteMapDataSource">
<%— <Items>
<asp:MenuItem NavigateUrl="~/Default.aspx" Text="Home"/>
<asp:MenuItem NavigateUrl="~/About.aspx" Text="About"/>
</Items>–%>
</asp:Menu>
(Note that I left in the out of the box VS2010 template items for reference)
Voila – menu trimming
Behind the scenes, ASP.NET runtime knows to look for Web.Sitemap and then to look in your web.config for the roles
Once you move to MVC2, I thought all hope was lost. No more server controls. No more auto menu trimming. No more free ice cream. But, I was wrong. You can use ASP.NET Server controls in your MVC2 project and things work just fine. This is what I did:
I added a site map
<?xml version="1.0" encoding="utf-8" ?>
<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
<siteMapNode url="" title="" description="">
<siteMapNode url="" title="Home" description="">
<siteMapNode url="Home/Index" title="Index" description="" />
<siteMapNode url="Home/About" title="About Us" description="" />
</siteMapNode>
<siteMapNode url="" title="User Input" description="">
<siteMapNode url="UserInput/Index" title="Index" description="" />
</siteMapNode>
<siteMapNode url="" title="Private" description="">
<siteMapNode url="Private/CurrentTime" title="Current Time" description="" />
</siteMapNode>
</siteMapNode>
</siteMap>
The first thing to realize is that you are no longer mapping to physical file locations – you are still using the routing engine. Note that my siteamp does not have a .aspx suffix nor a \Views subdirectory listed. Also, if you have the file location on disk but no controller, you get a 404:
I then added the same SiteMapProvider and Location syntax to the web.config. The then added the SiteMapDataSource to the Master page with the menu.
<div id="menucontainer">
<form runat="server">
<asp:SiteMapDataSource runat="server" ID="smds" ShowStartingNode="false" />
<asp:Menu runat="server" ID="aspmenu" DataSourceID="smds" />
</form>
<%— <ul id="menu">
<li><%: Html.ActionLink("Home", "Index", "Home")%></li>
<li><%: Html.ActionLink("About", "About", "Home")%></li>
</ul>–%>
</div>
(Note that I left in the out of the box VS2010 template items for reference)
(also note that I had to add a form tag around the provider and menu)
I ran it – to my <slight> surprise, it worked – sorta:
I worry about the formatting later – at least it is showing up. Alas, no menu trimming though!
Interestingly, looking at the HTTP via Fiddler, you can see the view state:
Here are the problems:
· Hard-Coded URLs in the sitemap
· Permissions tied to File System locations
· View State in MVC – Say it aint’s so!
I wonder if there is a way to create a SiteMap provider based on the Routing Engine? A quick search showed this one here and here.
But I wanted to try to extend the XMLSiteMapProvider to account for the routes. But then, it is not an XMLSiteMapProvider. In fact, it is a RoutingEngineSiteMapProvider.
My next blog post continues this idea/rabbit hole.