ASP.NET MVC and Menu Trimming

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.

 

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: