MvcSiteMapProvider ошибка с разбиением на страницы

При использовании нумерации страниц URL-адрес генерации неправильного ASP.NET MVC продолжается, но я обнаружил, как это исправить. Как это исправить при использовании @Html.MvcSiteMap().SiteMapPath() я не могу понять.

Проблема в том, когда в действиях ShowForum или ShowTopic и когда я использую пагинацию какой-то форум или тему. В @Html.MvcSiteMap().SiteMapPath() я получаю URL на родительской странице с номером страницы

ОБНОВИТЬ

Для настройки маршрута я использую атрибут маршрута

    [HttpGet]
    [Route("{forumName}", Name = "showForum", Order = 6)]
    [Route("{forumName}/Page/{page}", Order = 5)]
    [OutputCache(Duration = 30, VaryByParam = "forumName;page", Location = OutputCacheLocation.ServerAndClient)]
    public async Task<ActionResult> ShowForum(string forumName, int page = 1)

    [HttpGet]
    [RefreshDetectFilter]
    [Block(VisibleBlock = false)]
    [Route("{forum}/{topicName}", Name = "showTopic", Order = 8)]
    [Route("{forum}/{topicName}/Page/{page}", Order = 7)]
    [OutputCache(Duration = 30, VaryByParam = "topicName;page", Location = OutputCacheLocation.ServerAndClient)]
    public async Task<ActionResult> ShowTopic(string forum, string topicName, int page = 1)

Мой форум DynamicNodeProvider

    public override IEnumerable<DynamicNode> GetDynamicNodeCollection(ISiteMapNode node)
    {
        var rootTitle = ManagerLocalization.Get("Forums", "FORUMS");
        var pageParameter = new List<string> { "page" };
        var url = "~/Forums";
        var attr = new Dictionary<string, object> { { "Controller", "Forums" } };

        var nodes = new List<DynamicNode>
                        {
                            new DynamicNode
                                {
                                    Key = "forum_home",
                                    Title = rootTitle,
                                    Url = url,
                                    Attributes = attr
                                }
                        };

        var forums = this._forumsService.GetAllForumsForMap();
        var topics = this._forumsService.GetAllTopicsForMap();

        foreach (var forum in forums)
        {
            var forumRouteValue = new Dictionary<string, object> { { "forumName", forum.NameTranslit } };

            nodes.Add(new DynamicNode
            {
                ParentKey = forum.ForumId != -1 ? $"forum_{forum.ForumId}" : "forum_home",

                Key = $"forum_{forum.Id}",
                Title = forum.Name,
                PreservedRouteParameters = pageParameter,
                Controller = "Forums",
                Action = "ShowForum",
                RouteValues = forumRouteValue,

            });

            var forumTopics = topics.Where(item => item.ForumId == forum.Id);

            foreach (var topic in forumTopics)
            {
                var topicRouteValue = new Dictionary<string, object> { { "forum", forum.NameTranslit }, { "topicName", topic.TitleTranslite } };

                nodes.Add(new DynamicNode
                {
                    ParentKey = $"forum_{forum.Id}",
                    Key = $"topic_{topic.Id}",
                    Title = topic.Title,
                    PreservedRouteParameters = pageParameter,
                    Controller = "Forums",
                    Action = "ShowTopic",
                    RouteValues = topicRouteValue,
                });
            }
        }

        return nodes;
    }

2 ответа

Решение

Я нашел, как это исправить, спасибо NightOwl888. Я не первый раз понял, что надо делать.

Сначала я удалил инициализацию PreservedRouteParameters в ForumDynamicNodeProvider

Второе я добавил в действие

        if (forumPage > 1)
        {
            var node = SiteMaps.Current.FindSiteMapNodeFromKey(forumName);

            if (node != null)
            {
                node.RouteValues["forumPage"] = forumPage;
            }
        }

Также мне нужно изменить дерево генерации в ForumDynamicNodeProvider, потому что SiteMaps.Current не работает в асинхронном режиме.

Проблема в том, что вы используете одно и то же имя ключа маршрута {page} в двух разных местах в одном и том же узле родословной в сочетании с PreservedRouteParameters, PreservedRouteParameters получает свои данные из текущего запроса. Поэтому важно, чтобы ключ маршрута имел одинаковое значение в каждом запросе в одной и той же родословной узла. Чтобы он правильно работал с PreservedRouteParamters Вам нужно сделать три вещи:

  1. Используйте разные ключи маршрута для каждого отдельного параметра страницы (например, {forumPage} а также {page}).
  2. Убедитесь, что параметр страницы-предка передан в запрос его потомков, поэтому при построении URL-адреса для узла-предка значение находится в текущем запросе. Самый простой способ - создать URL с информацией о страницах всех предков ({forumName}/Page/{forumPage}/{topicName}/Page/{page}).
  3. Любые ключи маршрута, имеющие одинаковое значение между узлами, должны оставаться одинаковыми ({forumName} в обоих направлениях).

Затем вам нужно добавить параметры при построении URL дочернего узла. Вы должны создать URL-адрес вручную в своем приложении, потому что запрос не будет иметь все параметры, если вы не сделаете это.

@Html.ActionLink("TheTopicName", "ShowTopic", "Forums", 
    new { forumName = 1, forumPage = 2, topicName = "foo", page = 1 }, null)

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

Увидеть MvcSiteMapProvider-Forcing-A-Match-2-Levels проект в загрузке кода для Как заставить MvcSiteMapProvider запомнить позицию пользователя для аналогичной конфигурации и решения. В этом случае он использует productId вместо forumPage в качестве параметра, который сохраняется на узлах-потомках, чтобы вы могли вернуться к родительскому продукту.

Обратите внимание, что вы можете использовать аналогичную конфигурацию (с PreservedRouteParameters а также SiteMapTitleAttribute) для всего вашего форума, а не с использованием провайдера динамических узлов. Однако в этом случае я бы предложил отключить /sitemap.xml конечной точки и бросить свой собственный.

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