Как я могу остановить ASP.Net MVC Html.ActionLink от использования существующих значений маршрута?
-
08-07-2019 - |
Вопрос
Веб-сайт, над которым я работаю, имеет несколько довольно сложных структур маршрутизации, и мы испытываем некоторые трудности при работе с механизмом маршрутизации для создания URL-адресов так, как нам нужно их создавать.
У нас есть страница результатов поиска, которая использует сопоставление с шаблоном на основе RegEx для группировки нескольких переменных в один сегмент маршрута (т. е. "www.host.com/ {StructureParameters}" может быть следующим: "www.host. com / variableA-variableB-variableC "- где переменные от A до C являются необязательными). Это работает для нас хорошо после небольшой работы. Р>
Проблема, с которой мы сталкиваемся, решается вокруг раздражающей функции метода ActionLink: если вы укажете на тот же контроллер / действие, он сохранит существующие значения маршрута, хотите вы их или нет. Мы предпочитаем контролировать то, как выглядят наши ссылки, и в некоторых случаях нельзя сохранять существующие параметры. Примером может служить то, что основная навигация нашего сайта ведет на страницу результатов поиска без заданных параметров - страницу поиска по умолчанию, если хотите. Я говорю, что это раздражающая функция, потому что это редкий экземпляр ASP.Net MVC Framework, который, по-видимому, диктует реализацию без очевидной точки расширения - мы бы предпочли не создавать пользовательский код ActionLink для записи простой навигационной ссылки на нашей главной странице! р>
Я видел, как некоторые говорили, что вам нужно явно установить такие параметры, чтобы они были пустыми строками, но когда мы пытаемся это сделать, это просто изменяет параметры из значений маршрута в параметры строки запроса. Мне кажется неправильным, что мы должны явно исключать значения, которые мы явно не передаем в качестве параметров методу ActionLink, но если это наша единственная опция, мы будем ее использовать. Однако в настоящее время, если он отображается в строке запроса, он для нас настолько же бесполезен, как и ввод параметров непосредственно в маршрут.
Я знаю, что наша структура маршрутизации усугубляет эту проблему - у нас, вероятно, не было бы никаких проблем, если бы мы использовали более простой подход (например, www.host.com/variableA/variableB/variableC), но наша структура URL не подлежит обсуждению - он был разработан для удовлетворения особых потребностей, связанных с юзабилити, SEO и обменом ссылками / контентом.
Как мы можем использовать Html.ActionLink для генерации ссылок на страницы, не обращаясь к текущим данным маршрута (или, если возможно, без необходимости явно исключать сегменты маршрута), даже если эти ссылки приводят к одним и тем же методам действий?
Если нам нужно явно исключить сегменты маршрута, как мы можем предотвратить отображение метода маршрутами в качестве параметров строки запроса?
Эта, казалось бы, небольшая проблема вызывает у нас удивительное количество горя, и я буду благодарен за любую помощь в ее решении.
РЕДАКТИРОВАТЬ: по запросу LukLed, вот пример вызова ActionLink:
// I've made it generic, but this should call the Search action of the
// ItemController, the text and title attribute should say "Link Text" but there
// should be no parameters - or maybe just the defaults, depending on the route.
//
// Assume that this can be called from *any* page but should not be influenced by
// the current route - some routes will be called from other sections with the same
// structure/parameters.
Html.ActionLink(
"Link Text",
"Search",
"Item",
new { },
new { title = "Link Text" }
);
Решение
Установка значения маршрута в нулевую или пустую строку при вызове Html.ActionLink
или Html.RouteLink
(или любого метода генерации URL) удалит " ambient " значения маршрута.
Например, со стандартным маршрутом контроллера / действия / идентификатора MVC предположим, что вы находитесь на "Home / Index / 123". Если вы вызываете Html.RouteLink (new {id = 456})
, тогда MVC заметит " ambient " значения маршрута controller = " Home "
и action = " Index "
. Он также заметит значение окружающего маршрута id = "123"
, но оно будет перезаписано явным " 456 " ;. Это приведет к тому, что сгенерированный URL будет «Home / Index / 456».
Порядок параметров также имеет значение. Например, скажем, вы назвали Html.RouteLink (new {action = " About "})
. & Quot; О " действие перезапишет текущий " индекс " действие и " идентификатор " параметр будет полностью очищен! Но почему, спросите вы? Потому что как только вы сделаете недействительным сегмент параметра, все сегменты параметра после него станут недействительными. В этом случае «действие» был признан недействительным новым явным значением, поэтому «id», который идет после него и не имеет явного значения, также становится недействительным. Таким образом, сгенерированный URL будет просто "Home / About" (без удостоверения личности).
В этом же сценарии, если вы вызвали Html.RouteLink (new {action = " "})
, сгенерированный URL будет просто " Home " потому что вы аннулировали действие " action " с пустой строкой, а затем это вызвало " id " быть также признанным недействительным, потому что оно пришло после недействительного " действия ".
Другие советы
Решение в корне проблемы
Похоже, что оптимальное решение (которое не пахнет как обходной путь) - это то, которое решает проблему там, где у него есть корни, а именно в маршрутизации.
Я написал собственный класс Route
с именем RouteWithExclusion
, который может определять имена значений маршрутов, которые следует исключать / удалять при создании URL-адресов. Проблема заключается в том, что при маршрутизации не выполняется таблица маршрутов, а последующие маршруты не имеют одинаковых имен значений маршрутов ...
Вся проблема подробно описана и объяснена в мой пост в блоге и весь код там тоже есть. Проверьте это, это может помочь вам решить эту проблему маршрутизации. Я также написал два дополнительных метода расширения MapRoute
, которые принимают дополнительный параметр.
Если вы хотите полностью контролировать ссылку, просто создайте ее самостоятельно:
<a href="~/variableA/variableB/<%= Html.Encode(Model.Target) %>">Click Here</a>
Замените все, что вам нужно, в атрибуте href
.