Создайте ActionLink / RouteLink из Paging UserControl, который использует текущие значения маршрута и состояние модели - PullRequest
3 голосов
/ 11 марта 2010

Я реализую сайт, в котором есть поиск, который можно выполнить с помощью методов Controller, доступ к которым осуществляется по двум различным маршрутам. Один из них зависает от маршрута по умолчанию (с использованием либо данных Post, либо значений строки запроса для параметров поиска), а второй - URL-адреса оптимизации SEO, который получает местоположение и фразу через два значения маршрута. Второй маршрут выглядит так:

routes.MapRoute("SEOSearch", "Search/{seoLocation}/{seoSearchString}",
  new { controller = "Search", 
        action = "SEOResults", 
        seoLocation = (string)null, 
        seoSearchString = (string)null });

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

Как я уже сказал, первый маршрут - это маршрут по умолчанию /controller/action/id, и правильный контроллер / действие для этого - "Поиск" и "Индекс".

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

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

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

Что я хочу

Итак, если вы перешли на /Search?Location=[location]&Phrase=[phrase], я хочу, чтобы сгенерированная пейджером ссылка на странице 2 была /Search?Location=[location]&Phrase=[phrase]&Page=2.

Однако, если вы запустили поиск с помощью /Search/[location]/[phrase], я хочу, чтобы ссылка на странице 2 была /Search/[location]/[phrase]?Page=2.

Что у меня есть

Самое близкое, что у меня есть, это:

<%=  Html.RouteLink("Previous Page", 
       RouteHelpers.Combine(ViewContext.RouteData.Values, 
       new RouteValueDictionary() { { "Page", Model.Results.PageNo + 1}})) %>

Где RouteHelpers.Combine - это написанное мной расширение, которое берет два объекта и объединяет их в один RouteValueDictionary. Взяв значения RouteValues ​​для текущего запроса, я могу сохранить текущее имя контроллера и действия (без необходимости знать, какие они есть) - однако при этом пропускается некоторая важная информация из ModelState - то есть любые дополнительные параметры поиска, которые были предоставлены - т.е. он работает, если текущий Url /Search/London/Widgets, но если /Search/London/Widgets?PageSize=50, то параметр PageSize не сохраняется в исходящей ссылке.

Еще хуже, если это URL, не относящийся к SEO - то есть /Search?Location=London&Phrase=Widgets, исходящий URL просто становится /Search?Page=x.

Мои параметры поиска считываются из запроса в тип модели, который затем передается как на страницу хоста, так и на сам пейджер, так что в теории я мог бы просто всегда генерировать их из этого - но я получаю все параметры в URL, даже если они являются значениями по умолчанию (поэтому их не нужно указывать), поэтому URL выглядит ужасно.

Как мне добиться того, чего я хочу !? Я чувствую, что ничего не знаю о MVC внезапно!

1 Ответ

3 голосов
/ 15 марта 2010

Вам не нужно использовать RouteHelper для объединения значений маршрута. Эти значения автоматически объединяются с вашим анонимным объектом, когда вы используете ActionLink. Все существующие значения будут перезаписаны и добавлены новые. Этот звонок сделает это за вас:

RouteValueDictionary values = RouteValuesHelpers.MergeRouteValues(
    actionName,
    controllerName,
    requestContext.RouteData.Values,
    routeValues,
    includeImplicitMvcValues); // true for ActionLink; false for RouteLink

Где routeValues - ваши значения от анонимного объекта. Они объединяются в requestContext.RouteData.Values.

Так что вы все еще можете использовать:

Html.ActionLink(
    "whatever",
    this.ViewContext.RouteData.Values["action"],
    this.ViewContext.RouteData.Values["controller"],
    new { Page = /* whatever needs to be */ },
    null)

Нуль в конце является обязательным, поэтому он не должен путать анонимный объект с атрибутами HTML.

Но у вас есть проблемы с маршрутизацией, если вы также не наложили ограничение маршрута на маршрут по умолчанию, чтобы использовать только определенные действия, в противном случае ваш /Search/SeoLocation/SeoSearchString все равно будет обрабатываться вашим маршрутом по умолчанию, SeoLocation станет вашим действием и SeoSearchString id.

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

...