2

Suppose I have 3 areas on my page that have links

  • Header
  • Menu
  • Footer

Each have different links, but some links overlap:

Overview

I am using MVCSiteMapProvider to accomplish this. I have a SiteMap:

<?xml version="1.0" encoding="utf-8" ?>
<mvcSiteMap xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-3.0"
    xsi:schemaLocation="http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-3.0 MvcSiteMapSchema.xsd"
    enableLocalization="false">

    <mvcSiteMapNode title="Home" controller="Home" action="Index">

        <mvcSiteMapNode title="Link 1" controller="" action="" visibility="Header, Footer" />
        <mvcSiteMapNode title="Link 2" controller="" action="" visibility="Menu" />
        <mvcSiteMapNode title="Link 3" controller="" action="" visibility="Header, Menu" />
        <mvcSiteMapNode title="Link 4" controller="" action="" visibility="Menu, Footer, Header" />

    </mvcSiteMapNode>

</mvcSiteMap>

I thought that maybe Visibility was the way to do this, but it doesn't work the way I want it.

Public Class MenuVisibilityProvider
    Implements ISiteMapNodeVisibilityProvider

    Public Function IsVisible(ByVal node As SiteMapNode, ByVal context As HttpContext, ByVal sourceMetadata As IDictionary(Of String, Object)) As Boolean Implements ISiteMapNodeVisibilityProvider.IsVisible
        Dim visibility As String = node("visibility")

        If visibility IsNot Nothing Then Return True

        Select Case visibility
            Case "Menu"
            Case "Header"
            Case "Footer"
                Return True
        End Select

        Return False
    End Function
End Class

I end up with all of the links in every area.

Edit for clarification:

This is a similar question, but also with no answer: https://stackoverflow.com/questions/12845929/how-to-show-partial-site-map-including-current-node-with-mvcsitemapprovider

Also similar, but I don't want to have to make multiple SiteMaps: Using Multiple MvcSiteMaps

Community
  • 1
  • 1
Rowan Freeman
  • 15,724
  • 11
  • 69
  • 100

1 Answers1

2

OP here. I accomplished this using only one site map.

To do this:

  1. I added visibility tags to each sitemap element, for example:

    <mvcSiteMapNode title="Login" controller="Members" action="Login" visibility="SideMenu Footer" />
    

    In this example "SideMenu Footer" are my tags. I will use String.Contains() later to determine visibility.

  2. I added multiple different siteMap providers in the Web.config with different siteMapNodeVisibilityProvider:

    <siteMap defaultProvider="MvcSiteMapProvider" enabled="true">
        <providers>
            <clear />
            <add name="MvcSiteMapProvider" type="MvcSiteMapProvider.DefaultSiteMapProvider, MvcSiteMapProvider" siteMapFile="~/Mvc.Sitemap" securityTrimmingEnabled="true" cacheDuration="5" enableLocalization="true" scanAssembliesForSiteMapNodes="true" includeAssembliesForScan="" excludeAssembliesForScan="" attributesToIgnore="visibility" nodeKeyGenerator="MvcSiteMapProvider.DefaultNodeKeyGenerator, MvcSiteMapProvider" controllerTypeResolver="MvcSiteMapProvider.DefaultControllerTypeResolver, MvcSiteMapProvider" actionMethodParameterResolver="MvcSiteMapProvider.DefaultActionMethodParameterResolver, MvcSiteMapProvider" aclModule="MvcSiteMapProvider.DefaultAclModule, MvcSiteMapProvider" siteMapNodeUrlResolver="MvcSiteMapProvider.DefaultSiteMapNodeUrlResolver, MvcSiteMapProvider" siteMapNodeVisibilityProvider="MvcSiteMapProvider.DefaultSiteMapNodeVisibilityProvider, MvcSiteMapProvider" siteMapProviderEventHandler="MvcSiteMapProvider.DefaultSiteMapProviderEventHandler, MvcSiteMapProvider" />
            <add name="NavSiteMapProvider"  ... siteMapNodeVisibilityProvider="RootNamespace.Namespace.NavVisibilityProvider, RootNamespace" ... />
            <add name="FooterSiteMapProvider"  ... siteMapNodeVisibilityProvider="RootNamespace.Namespace.FooterVisibilityProvider, RootNamespace" ... />
        </providers>
    </siteMap>
    
  3. I created a new code file (class) called CustomVisibilityProvider. Inside I created a class for each provider (Footer, Nav, Menu etc)

    ' Note: VB.NET :P
    Public Class MenuVisibilityProvider
        Implements ISiteMapNodeVisibilityProvider

        Public Function IsVisible(ByVal node As SiteMapNode, ByVal context As HttpContext, ByVal sourceMetadata As IDictionary(Of String, Object)) As Boolean Implements ISiteMapNodeVisibilityProvider.IsVisible

            Dim visibility As String = node("visibility")

            If visibility Is Nothing Then Return False

            If visibility.Contains("Menu") Then Return True

            Return False
        End Function

    End Class

    Public Class NavVisibilityProvider
        Implements ISiteMapNodeVisibilityProvider

        ...
            If visibility.Contains("Nav") Then Return True
        ...
    End Class
  1. When you're in a view file:

    @Html.MvcSiteMap("FooterSiteMapProvider").Menu
    

Note: You can give the Menu() a custom view also, so that nav, footer, menu etc render the links differently (some might be in <ul></ul> format while others might be <a> tags).

Rowan Freeman
  • 15,724
  • 11
  • 69
  • 100