ASP.NET MVC Url.Action добавляет текущие значения маршрута к сгенерированному URL - PullRequest
53 голосов
/ 20 августа 2011

Я видел этот вопрос пару раз здесь, в SO, но ни один из них не дал приемлемого ответа:

ASP.NET MVC @ Url.Action включает данные текущего маршрута
ASP.NET MVC неявно добавляет значения маршрута

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

Если я делаю что-то вроде этого:

Url.Action("Group", "Groups");

С главной страницы сайта (/) он возвращает URL-адрес, подобный этому:

"mysite.com/Groups/Group"

, что нормально Теперь, если текущий адрес сайта / Groups / Group / 1, и я вызываю тот же метод

Url.Action("Group", "Groups");

, возвращаемый URL-адрес будет таким:

"mysite.com/Groups/Group/1"

При создании URL-адреса автоматически добавляется значение маршрута для текущей страницы.Даже если я сгенерирую URL следующим образом:

Url.Action("Group", "Groups", null);

Таким образом, явно указав, что я не хочу никаких значений маршрута, сгенерированный URL остается тем же.Чтобы получить нужный адрес, я должен явно установить значение маршрута в пустую строку, например так:

Url.Action("Group", "Groups", new {id=""});

Это сгенерирует следующий URL:

"mysite.com/Groups/Group"

Мой вопроспочему это происходит?Если я не установил значения маршрута, он не должен добавлять их к сгенерированному URL.

Ответы [ 7 ]

50 голосов
/ 20 августа 2011

Url.Action будет повторно использовать текущие параметры запроса, если вы не установили их явно.Это предусмотрено в алгоритме сопоставления исходящих URL.При поиске параметров данных маршрута в процессе создания URL-адреса параметры берутся из:

1) явно предоставленных значений

2) значений из текущего запроса

3) значения по умолчанию

В указанном выше порядке.

Алгоритм сопоставления исходящих запросов для маршрутов сложен, поэтому рекомендуется явно задавать все параметры для запроса, как вы делали в своем примере

2 голосов
/ 10 марта 2017

Простой пример:

public class ProductController : Controller
{
  public ActionResult Edit(int id)
  {
    return View();
  }

  [Route("Product/Detail/{id:int}")]
  public ActionResult Detail(int id)
  {
    return View();
  }
}

Представление «Правка» содержит только это:

@{ Layout = null;}
@Url.Action("Detail", "Cmr")

Поэтому, когда вы запускаете свой сайт, например localhost:randomPort/Product/Edit/123, вы получаете следующий ответ: /Product/Detail/123

Почему?Поскольку атрибут Route имеет обязательный параметр id.Параметр Id читается из URL, хотя мы написали только Url.Action(methodName, controller) - без указания параметра.Также не имеет смысла иметь подробности метода без идентификатора.

Для работы атрибутов необходимо добавить следующую строку к RouteConfig.cs:

public static void RegisterRoutes(RouteCollection routes)
{
  ...
  routes.MapMvcAttributeRoutes();
  ...
}
2 голосов
/ 28 апреля 2013

Поэтому, когда я прочитал ответ objectbox, я подумал, что мне придется изменить несколько ссылок в моем коде.Затем я попытался добавить маршрут по умолчанию, исключив параметры по умолчанию, что решило проблему:

routes.MapRoute(
    "ArtistArtworkDefPage",
    "Artist/{username}/Artwork",
    new
    {
        controller = "Artist",
        action = "Artwork",
        page = 1
    }
);

routes.MapRoute(
    "ArtistArtwork",
    "Artist/{username}/Artwork/{page}",
    new
    {
        controller = "Artist",
        action = "Artwork",
        page = 1
    },
    new { page = @"\d+" }
);
2 голосов
/ 02 апреля 2013

Мое приложение явно устанавливает значения маршрута и не хочет магического значения из текущего запроса.Я хочу быть в полном контроле.

Я сделал расширение, которое сосуществует с моей коллекцией библиотеки маршрутов. Отсюда единственный параметр RouteValueDictionary.(См. Мой комментарий к библиотеке маршрутов внизу)

Здесь я удаляю все значения маршрутов из запроса до генерации URL.

(примечание: для массива. Содержит часть игнорируемого регистра см. Как сделать Array. Содержит регистр-нечувствительный массив строк? )

public static string Action(this UrlHelper helper, 
                            RouteValueDictionary routeValues)
{
    RemoveRoutes(helper.RequestContext.RouteData.Values);

    string url = helper.Action(routeValues["Action"].ToString(), routeValues);
    return url;
}

public static void RemoveRoutes(RouteValueDictionary currentRouteData)
{
    List<string> keyList = new List<string>(currentRouteData.Keys);

    string[] ignore = new[] { "Area", "Controller", "Action" };
    foreach (string key in keyList)
    {
        if (!ignore.Contains(key, StringComparer.CurrentCultureIgnoreCase))
            currentRouteData.Remove(key);
    }
}

У меня есть методы расширения Form и ActionLink, которые используют метод RemoveRoutes.Ни один помощник в моей библиотеке mvc не использует метод, который не является методом расширения, который я создал.Таким образом, все маршрутизируемые данные очищаются перед генерацией URL.

Для справки я использую AttributeRouting.Вот пример одного маршрута из моей библиотеки маршрутов.

public static RouteValueDictionary DisplayNews(int newsId)
{
    RouteValueDictionary route = new RouteValueDictionary();
    route["Area"] = _area;
    route["Controller"] = _controller;
    route["Action"] = "DisplayNews";
    route["newsId"] = newsId;
    return route;
}
1 голос
/ 01 декабря 2017

Это обходной путь, который не требует маршрутизации атрибута и не изменяет текущие значения маршрута в вашем запросе.Эта идея взята из http://notherdev.blogspot.ca/2013/10/aspnet-mvc-current-values-used-by-url-action.html,, который я немного изменил, чтобы работать без MvcFutures.

Я построил свое собственное расширение Action в UrlHelper с дополнительным bool, который позволяет вам при необходимости игнорировать текущие значения маршрутачтобы не конфликтовать с существующими методами Action в UrlHelper.)

Он создает абсолютно новый RequestContext из текущего, используя текущий маршрут, но не текущие значения маршрута,Затем мы передаем это базовым помощникам.Таким образом, когда базовые помощники пойдут посмотреть на значения маршрута из контекста запроса, они не найдут ни одного и, следовательно, не будут использовать их при генерации URL.

public static string Action(this UrlHelper urlHelper, string actionName, string controllerName, object routeValues, bool ignoreCurrentRouteValues=false) {
    var routeValueDictionary = new RouteValueDictionary(routeValues);
    var requestContext = urlHelper.RequestContext;
    if (ignoreCurrentRouteValues) {
        var currentRouteData = requestContext.RouteData;
        var newRouteData = new RouteData(currentRouteData.Route, currentRouteData.RouteHandler);
        requestContext = new RequestContext(requestContext.HttpContext, newRouteData);
    }

    return UrlHelper.GenerateUrl(null, actionName, controllerName, routeValueDictionary,
        urlHelper.RouteCollection, requestContext, includeImplicitMvcValues: false);
}
0 голосов
/ 28 апреля 2016

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

@{
    var current_route_1 = new RouteValueDictionary(Url.RequestContext.RouteData.Values);
    var current_route_2 = new RouteValueDictionary(Url.RequestContext.RouteData.Values);

    //If you want to customize the routing values
    current_route_1["controller"] = "Controller1";
    current_route_2["controller"] = "Controller2";
}

@Url.RouteUrl(current_route_1);
@Url.RouteUrl(current_route_2);
0 голосов
/ 18 августа 2015

Простой обходной путь - сначала вызвать

Url.Action("dummy", new { ... }) 

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...