Почему карта сайта MVC скрывает пункты меню, где существуют действия на контроллере?

Я использую карту сайта MVC для MVC3, но у меня проблемы с ней. Рассмотрим следующий файл карты сайта:

<?xml version="1.0" encoding="utf-8" ?>
<mvcSiteMap xmlns="http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-3.0" enableLocalization="true">
  <mvcSiteMapNode title="Home" controller="Home" action="Index" changeFrequency="Always" updatePriority="Normal" Description="Test HOME">
    <mvcSiteMapNode title="Today" controller="Dashboard" action="Today" />
    <mvcSiteMapNode title="Today1" controller="Dashboard" action="Today1" />
    <mvcSiteMapNode title="Today2" controller="Dashboard" action="Today2" />
    <mvcSiteMapNode title="Today3" controller="Dashboard" action="Today3" />
    <mvcSiteMapNode title="Today4" controller="Dashboard" action="Today4" />   
  </mvcSiteMapNode>
</mvcSiteMap>

Когда я загружаю свою веб-страницу, я получаю только следующие опции:

Сегодня1, Сегодня2, Сегодня3, Сегодня4

Но сегодня не отображается. Это действие на контроллере, тогда как другие действия не существуют. Почему он скрывает элемент, который фактически существует на контроллере? Я снял авторизацию на контроллере, чтобы исключить, что он имеет какое-либо отношение к авторизации, но все же эффект.

Это конфиг карты сайта (установлен в web.config):

  <siteMap defaultProvider="MvcSiteMapProvider" enabled="true">
      <providers>
        <clear />
        <add name="MvcSiteMapProvider" 
             type="MvcSiteMapProvider.DefaultSiteMapProvider, MvcSiteMapProvider" 
             siteMapFile="~/Mvc.Sitemap" 
             securityTrimmingEnabled="true" 
             cacheDuration="5" 
             enableLocalization="true"
             scanAssembliesForSiteMapNodes="false" 
             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" />
      </providers>      
    </siteMap>
  </system.web>

2 ответа

Решение

Я выясняю проблему. Метод InRole() пользователя HttpContext используется в модуле MvcSiteMapProvider.DefaultAclModule в коде библиотеки. Я использую проверку подлинности с помощью форм, что означает, что InRole никогда не будет работать, так как свойство Роли в пользовательском контексте не установлено (оно не знает, как применяются роли).

Я мог бы либо написать свой собственный поставщик aclmodule, который проверяет билет аутентификации для ролей, хранящихся в билете, либо, альтернативно, для каждого события запроса аутентификации в global.asax, устанавливать контекст с установленными ролями. В итоге я выбрал последнее:

например

  if (HttpContext.Current.User != null)
        {
            if (HttpContext.Current.User.Identity.IsAuthenticated)
            {
                if (HttpContext.Current.User.Identity is FormsIdentity)
                {                     
                    FormsIdentity formsId = (FormsIdentity)HttpContext.Current.User.Identity;
                    FormsAuthenticationTicket ticket = formsId.Ticket;

                    // need to do this so MVC sitemap IsInRole works inside default acl module: MvcSiteMapProvider.DefaultAclModule
                    var authData = new AuthenticationModel(ticket.UserData);
                    var roles = new List<string>(authData.EffectiveRoles).ToArray();
                    HttpContext.Current.User = new GenericPrincipal(formsId, roles);
                }
            }
        }

@jaffa, твой подход помог мне!! Благодарю. Вот как я это реализовал.. может быть, это может помочь и другим!

public class MenuVisibilityController : Controller, ISiteMapNodeVisibilityProvider
{
    public bool IsVisible(SiteMapNode Node, HttpContext context, IDictionary<string, object> sourceMetadata)
    {
        return context.User.Identity.IsAuthenticated;
    }
}

Реализовал провайдера видимости для карты сайта MVC, а затем использовал его для видимости определенного узла, как показано ниже:

<mvcSiteMapNode title="Test Menu" controller="Account" action="Index" visibilityProvider="MyProject.Controllers.MenuVisibilityController, MyProject">
  <mvcSiteMapNode title="Test Item 1" controller="Account" action="GetItems" />
</mvcSiteMapNode>

указание реализованного контроллера в Visibility Provider должно служить цели.

Другие вопросы по тегам