MVCsiteMapProvider некоторые узлы совпадают, другие нет

Я использую MvcSiteMapProvider для создания хлебных крошек, и у меня возникают проблемы с сопоставлением узлов с новой функцией. Мы используем области MVC5 и последние библиотеки MvcSiteMapProvider.MVC5. Мы используем i18n с Resx файлами, наш атрибут title является ключом. URL-адреса наших страниц не меняются после выпуска, поэтому используйте стандартную конфигурацию XML.

Мы используем маршрутизацию на основе атрибутов MVC5.

Действие List является действием по умолчанию как для домашнего контроллера, так и для области, так же как и на маршруте Store/. Работает нормально, совпадение установлено.

Маршрут Search действия Store/Search не соответствует узлу.

Конфигурация

<mvcSiteMap xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns="http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-4.0"
    xsi:schemaLocation="http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-4.0 MvcSiteMapSchema.xsd">

  <mvcSiteMapNode controller="Dashboard" action="Index" title="Foobar" key="Bar">

    <!-- quite a large file -->

    <mvcSiteMapNode area="Store" controller="Home" action="List" title="SiteMap_DocumentStore_Home_List" preservedRouteParameters="page, itemsPerPage, msg">
      <mvcSiteMapNode area="Store" controller="Home" action="Search" title="SiteMap_DocumentStore_Search" preservedRouteParameters="tags, page"/>

      <!-- snip extra entries -->
    </mvcSiteMapNode>
  </mvcSiteMapNode>
</mvcSiteMap>

Я ценю, что могу удалить атрибуты area и controller из mvcSiteMapNode дочерних элементов List. Я оставил их здесь для полноты картины.

Домашний контроллер

[RouteArea("Store")]
[Route("{action=list}")]
public class HomeController : Controller
{
  [Route("{page?}/{itemsPerPage?}")]
  public ActionResult List(int page = 1, int itemsPerPage = -1, string msg = "")
  {}

  [Route("Search/{tags?}/{page?}")]
    public ActionResult Search(string tags = "", int page = 1)
  {}
}

Расследование

У меня есть ощущение, что это как-то связано с маршрутом MVC для действия List, которое пусто. Если я изменю маршрут List на:

[Route("List/{page?}/{itemsPerPage?}")]
public ActionResult List(int page = 1, int itemsPerPage = -1, string msg = "")
{}

Тогда узел поиска будет соответствовать, как и его братья и сестры (которые я вырезал)

Изменить – упростить маршрутизацию

Я удалил маршрут по умолчанию для контроллера [Route("{action=list}")]. Проблема все еще сохраняется.


person Dr Rob Lang    schedule 23.11.2015    source источник


Ответы (1)


Проблема №1:

Согласно MSDN:

Маршрут по умолчанию

Вы также можете применить атрибут [Route] на уровне контроллера, зафиксировав действие в качестве параметра. Затем этот маршрут будет применяться ко всем действиям в контроллере, если для конкретного действия не был определен конкретный [маршрут], переопределяющий установленный по умолчанию в контроллере.

В вашем случае маршрут уровня контроллера по умолчанию будет полностью проигнорирован, потому что в каждом случае у вас есть маршрут на уровне действия, который переопределяет его.

Проблема №2:

Я изучил, почему он не соответствует, запустив новый проект MVC 5 в VS 2015 и добавив область и остальную часть вашей конфигурации. Некоторое время я недоумевал, почему он не работает.

Затем я обнаружил, что строительные леса связывают разные страницы макета для каждой области в /Area/<area name>/Views/_ViewStart.cshtml.

@{
    Layout = "~/Areas/Store/Views/Shared/_Layout.cshtml";
}

Я изменил его, чтобы использовать общий файл ViewStart.cshtml, а затем он показал навигационную цепочку.

@{
    Layout = "~/Views/Shared/_Layout.cshtml";
}

Проблема №3:

Кроме того, у вас есть проблема с сохраненными параметрами маршрута. Поскольку они всегда являются производными от текущего запроса, внутренний запрос всегда должен предоставлять все параметры своих предков. Более того, параметры родительского и дочернего элементов не должны иметь разного значения, поэтому, например, page должен ссылаться на одну и ту же страницу как для List, так и для Search. Другими словами, каждое имя ключа должно быть уникальным в пределах своего предка.

Если они совпадают, вы можете исправить это, просто добавив дополнительный параметр в URL-адрес поиска.

[Route("Search/{page?}/{itemsPerPage?}/{tags?}")]

В противном случае вы должны дать каждому параметру page другое имя.

См. Как заставить MvcSiteMapProvider запоминать позицию пользователя и демонстрационные ролики, включенные в качестве руководства.

person NightOwl888    schedule 29.11.2015
comment
Спасибо за помощь. Я не понимаю, как это отвечает на мой вопрос. Если использовать такой маршрут, как [Route("List/{page?}/{itemsPerPage?}")], то [Route("Search/{tags?}/{page?}")] тоже работает. Если я использую пустое действие для списка [Route("{page?}/{itemsPerPage?}")], то это не так. Параметры маршрута не имеют значения. - person Dr Rob Lang; 30.11.2015
comment
При использовании атрибутивной маршрутизации действие никогда не бывает пустым. Он является производным от метода действия. Маршрут [Route("{page?}/{itemsPerPage?}")] требует, чтобы часть URL-адреса действия отсутствовала, чтобы работать, но он по-прежнему использует имя действия из действия, для которого он объявлен в словаре значений маршрута. Этот маршрут будет соответствовать любому URL-адресу с двумя сегментами, потому что заполнители могут быть любыми. Работает это или нет, зависит от того, есть ли у вас какие-либо другие маршруты, которые соответствуют URL-адресу с 2 сегментами, зарегистрированными до этого маршрута - в маршрутизации .NET всегда побеждает первое совпадение. - person NightOwl888; 30.11.2015
comment
Замечательно, это, безусловно, имеет смысл. Я до сих пор не понимаю, почему SiteMapNode не совпадает с моим поисковым маршрутом. Извините, что так медленно! - person Dr Rob Lang; 30.11.2015
comment
См. мое редактирование выше. Я проверил совпадения узлов в этом случае, но убедитесь, что вы объявили @Html.MvcSiteMap().SiteMapPath() на правильной странице макета. Кроме того, см. эту демонстрацию, чтобы увидеть соответствие узлов в этом случае (но обратите внимание, что демонстрация не решить вопрос № 3 выше). - person NightOwl888; 30.11.2015