Реализация XmlSiteMapProvider по умолчанию не может использовать SiteMap.FindSiteMapNode?

Я просто обновляю MvcSiteMapProvider с версии 3 до версии 4.6.3.

Я вижу, что примечание обновления указывает:

В общем, любая ссылка на System.Web.SiteMap.Provider нужно будет обновить до MvcSiteMapProvider.SiteMaps.Current

Я пытаюсь получить узел Sitemap с помощью:SiteMaps.Current.FindSiteMapNode(rawUrl)

Но это всегда возвращает ноль

Я посмотрел в код. В карте сайта это фактически вызывает функцию:

    protected virtual ISiteMapNode FindSiteMapNodeFromUrlMatch(IUrlKey urlToMatch)
    {
        if (this.urlTable.ContainsKey(urlToMatch))
        {
            return this.urlTable[urlToMatch];
        }

        return null;
    }

Он пытается найти соответствие в таблице URL.

Я использую реализацию по умолчанию XmlSiteMapProvider,

Это определить var url = node.GetAttributeValue("url");

siteMapNode.Url = url;
siteMapNode.UrlResolver = node.GetAttributeValue("urlResolver");

Так что, если я не определил url или же urlResolver атрибут в файле.sitemap. Эти переменные устанавливаются в пустую строку, когда генерируют узел.

И когда эти узлы передаются AddNode функция в SiteMap,

При добавлении узла

bool isMvcUrl = string.IsNullOrEmpty(node.UnresolvedUrl) && this.UsesDefaultUrlResolver(node);

этот код проверит, есть ли url или же urlResolver

// Only store URLs if they are clickable and are configured using the Url
// property or provided by a custom URL resolver.
if (!isMvcUrl && node.Clickable)
{
    url = this.siteMapChildStateFactory.CreateUrlKey(node);

    // Check for duplicates (including matching or empty host names).
    if (this.urlTable
        .Where(k => string.Equals(k.Key.RootRelativeUrl, url.RootRelativeUrl, StringComparison.OrdinalIgnoreCase))
        .Where(k => string.IsNullOrEmpty(k.Key.HostName) || string.IsNullOrEmpty(url.HostName) || string.Equals(k.Key.HostName, url.HostName, StringComparison.OrdinalIgnoreCase))
        .Count() > 0)
    {
        var absoluteUrl = this.urlPath.ResolveUrl(node.UnresolvedUrl, string.IsNullOrEmpty(node.Protocol) ? Uri.UriSchemeHttp : node.Protocol, node.HostName);
        throw new InvalidOperationException(string.Format(Resources.Messages.MultipleNodesWithIdenticalUrl, absoluteUrl));
    }
}
// Add the URL
if (url != null)
{
    this.urlTable[url] = node;
}

Наконец, нет URL добавить в urlTable, что приводит к FindSiteMapNode не могу ничего найти.

Я не уверен, должна ли быть определенная конфигурация. Или я должен реализовать кастом XmlSiteMapProvider просто добавьте URL.

1 ответ

Решение

Экземпляры ISiteMapNodeProvider не могут использовать функцию FindSiteMapNode по двум причинам. Первое, что вы уже обнаружили, - это то, что поиск по URL может быть выполнен, только если вы явно задали атрибут url в конфигурации узла. Вторая причина заключается в том, что SiteMapBuilder не добавляет ни один из узлов в SiteMap до тех пор, пока все экземпляры ISiteMapNodeProvider не завершат работу, поэтому было бы спорным добавить URL-адрес в таблицу URL в любом случае.

Это может помочь, если вы объясните, что вы пытаетесь достичь.

Классы ISiteMapNodeProvider имеют полный контроль над данными, которые добавляются к экземплярам SiteMapNode, и они также имеют доступ к своему родительскому экземпляру SiteMapNode. Как правило, это все, что нужно для заполнения данных. Поиск другого SiteMapNode из объекта SiteMap при заполнении данных не поддерживается. Но пока интересующий вас узел заполняется в том же экземпляре ISiteMapNodeProvider, вы можете просто получить ссылку на него позже, сохранив его в переменной.

Обновить

Хорошо, я перечитал ваш вопрос и ваш комментарий, и теперь кажется, что вы смотрите не в том месте. MvcSiteMapProvider v4 больше не основан на модели Microsoft SiteMap-провайдера, поэтому использование XmlSiteMapProvider не имеет смысла, так как обойдёт всю реализацию. Единственный случай, когда это может иметь смысл, - это если у вас есть гибридное приложение ASP.NET и ASP.NET MVC, между которыми вы хотите сохранить согласованную структуру меню. Смотрите Обновление с v3 до v4.

Есть 2 этапа для работы с данными. Первый этап (ISiteMapBuilder и ISiteMapNodeProvider) загружает данные из различных источников (атрибуты XML, .NET, DynamicNodeProviders и пользовательские реализации ISiteMapNodeProvider) и добавляет их в граф объектов, который начинается с объекта SiteMap. Как и в модели Microsoft, эти данные хранятся в общем кеше и загружаются только по истечении срока действия кеша. Это та стадия, на которой вы сосредоточились, и определенно не имеет смысла искать здесь узлы.

Второй этап - когда делается индивидуальный запрос на доступ к данным. Вот где поиск данных на основе URL может иметь смысл, но уже есть встроенное свойство CurrentNode, которое находит узел, соответствующий текущему URL (или, скорее, текущему маршруту, так как мы имеем дело с MVC), который в большинстве случаев это лучший подход к поиску узла. Каждый узел имеет свойства ParentNode и ChildNodes, которые можно использовать для перехода вверх или вниз по дереву.

На этом втором этапе вы можете получить доступ к данным SiteMap в любой момент после события Application_Start, например, в действии контроллера, в одном из встроенных помощников HTML, шаблоне помощника HTML в /Views/Shared/DisplayTemplates/ каталог или пользовательский помощник HTML. Это точка в жизненном цикле приложения, которую вы можете назвать линиями SiteMaps.Current.FindSiteMapNode(rawUrl) или (более вероятно) SiteMaps.Current.CurrentNode чтобы получить экземпляр узла, чтобы вы могли проверить его свойство Attributes (пользовательские атрибуты).

public ActionResult About()
{
    ViewBag.Message = "Your app description page.";

    var currentNode = MvcSiteMapProvider.SiteMaps.Current.CurrentNode;

    string permission = currentNode.Attributes.ContainsKey("permission") ? currentNode.Attributes["permission"].ToString() : string.Empty;
    string programs = currentNode.Attributes.ContainsKey("programs") ? currentNode.Attributes["programs"].ToString() : string.Empty;
    string agencies = currentNode.Attributes.ContainsKey("agencies") ? currentNode.Attributes["agencies"].ToString() : string.Empty;

    // Do something with the custom attributes of the About page here

    return View();
}

Наиболее распространенное использование пользовательских атрибутов - это использование их в пользовательском шаблоне помощника HTML. Вот пользовательская версия /Views/Shared/DisplayTemplates/SiteMapNodeModel.cshtml шаблон, который отображает пользовательские атрибуты. Обратите внимание, что этот шаблон вызывается рекурсивно помощниками HTML MenuMapPath и SiteMap. Посмотрите на этот ответ для получения дополнительной помощи, если вы намерены сделать настройку HTML-помощника.

@model MvcSiteMapProvider.Web.Html.Models.SiteMapNodeModel
@using System.Web.Mvc.Html
@using MvcSiteMapProvider.Web.Html.Models

@if (Model.IsCurrentNode && Model.SourceMetadata["HtmlHelper"].ToString() != "MvcSiteMapProvider.Web.Html.MenuHelper")  { 
    <text>@Model.Title</text>
} else if (Model.IsClickable) {
    if (string.IsNullOrEmpty(Model.Description))
    {
        <a href="@Model.Url">@Model.Title</a>
    }
    else
    {
        <a href="@Model.Url" title="@Model.Description">@Model.Title</a>
    }
} else { 
    <text>@Model.Title</text>
}

@string permission = Model.Attributes.ContainsKey("permission") ? Model.Attributes["permission"].ToString() : string.Empty
@string programs = Model.Attributes.ContainsKey("programs") ? Model.Attributes["programs"].ToString() : string.Empty
@string agencies = Model.Attributes.ContainsKey("agencies") ? Model.Attributes["agencies"].ToString() : string.Empty

<div>@permission</div>
<div>@programs</div>
<div>@agencies</div>
Другие вопросы по тегам