ASP.NET MVC Html.ActionLink поддерживает значения маршрутов - PullRequest
11 голосов
/ 16 апреля 2010

У меня есть вопрос, который в значительной степени был задан здесь:

asp.net mvc Html.ActionLink () с сохранением значения маршрута, которое я не хочу

Тем не менее, окончательное решение - клудж, чистый и простой, и я действительно хотел бы понять, почему это происходит, если кто-то может объяснить мне это?

Для полноты можно очень легко воссоздать сценарий:

  • Создайте новое веб-приложение MVC.
  • Запустите его.
  • Перейдите на вкладку «О программе». Измените URL-адрес для чтения / Home / About / Flib - это, очевидно, приведет вас к действию с идентификатором «Flib», который нам не нужен.

Обратите внимание, что ссылка в верхнем меню «О» теперь фактически ссылается на / Home / About / Flib - насколько я могу судить, это неправильно, поскольку у меня теперь нет абсолютно никакого способа использовать ссылки сайта для возврата к / Home / О

Я действительно не понимаю, почему я должен быть вынужден изменить все мои Html.ActionLinks, чтобы включить new { id = string.Empty } для значений маршрута и ноль для htmlAttribs. Это кажется особенно странным, потому что я уже указал id = 0 как часть самого маршрута.

Надеюсь, мне здесь не хватает трюка.

Ответы [ 3 ]

13 голосов
/ 24 апреля 2010

Когда вы смотрите в исходный код ссылки действия, вы обнаруживаете, что

<%= Html.ActionLink("LinkText", "Action", "Controller"); %>

будет соответствовать

public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName) {
        return ActionLink(htmlHelper, linkText, actionName, controllerName, new RouteValueDictionary(), new RouteValueDictionary());
    }

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

Однако, далее в коде, где генерируется URL:

public static string GenerateUrl(string routeName, string actionName, string controllerName, RouteValueDictionary routeValues, RouteCollection routeCollection, RequestContext requestContext, bool includeImplicitMvcValues) {
        if (routeCollection == null) {
            throw new ArgumentNullException("routeCollection");
        }

        if (requestContext == null) {
            throw new ArgumentNullException("requestContext");
        }

        RouteValueDictionary mergedRouteValues = RouteValuesHelpers.MergeRouteValues(actionName, controllerName, requestContext.RouteData.Values, routeValues, includeImplicitMvcValues);

        VirtualPathData vpd = routeCollection.GetVirtualPathForArea(requestContext, routeName, mergedRouteValues);
        if (vpd == null) {
            return null;
        }

        string modifiedUrl = PathHelpers.GenerateClientUrl(requestContext.HttpContext, vpd.VirtualPath);
        return modifiedUrl;
    }

вы видите, что на requestContext ссылаются, который имеет доступ к routeData и routeCollections, которые будут содержать данные id. При создании VirtualPathForArea в следующей строке указывается значение id в вашем URL:

internal static VirtualPathData GetVirtualPathForArea(this RouteCollection routes, RequestContext requestContext, string name, RouteValueDictionary values, out bool usingAreas) {
        if (routes == null) {
            throw new ArgumentNullException("routes");
        }

        if (!String.IsNullOrEmpty(name)) {
            // the route name is a stronger qualifier than the area name, so just pipe it through
            usingAreas = false;
            return routes.GetVirtualPath(requestContext, name, values);
        }

        string targetArea = null;
        if (values != null) {
            object targetAreaRawValue;
            if (values.TryGetValue("area", out targetAreaRawValue)) {
                targetArea = targetAreaRawValue as string;
            }
            else {
                // set target area to current area
                if (requestContext != null) {
                    targetArea = AreaHelpers.GetAreaName(requestContext.RouteData);
                }
            }
        }

        // need to apply a correction to the RVD if areas are in use
        RouteValueDictionary correctedValues = values;
        RouteCollection filteredRoutes = FilterRouteCollectionByArea(routes, targetArea, out usingAreas);
        if (usingAreas) {
            correctedValues = new RouteValueDictionary(values);
            correctedValues.Remove("area");
        }

        VirtualPathData vpd = filteredRoutes.GetVirtualPath(requestContext, correctedValues);
        return vpd;
    }

Строка:

VirtualPathData vpd = filteredRoutes.GetVirtualPath(requestContext, correctedValues);

берет виртуальный путь (который является просто маршрутом) и возвращает его. Таким образом, виртуальный путь будет /Home/About/Flib

Затем, когда этот виртуальный путь возвращается, следующая строка использует его для установки URL-адреса клиента для ссылки действия:

 string modifiedUrl = PathHelpers.GenerateClientUrl(requestContext.HttpContext, vpd.VirtualPath);

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

3 голосов
/ 28 апреля 2010

Если я правильно понимаю, похоже, вам нужно зарегистрировать второй маршрут «Только для действий» и использовать Html.RouteLink. Сначала зарегистрируйте такой маршрут в вашем приложении при запуске:

routes.MapRoute("ActionOnly", "{controller}/{action}", new { controller = "Home", action = "Index" } );

Тогда вместо ActionLink для создания этих ссылок используйте:

Html.RouteLink("About","ActionOnly")
1 голос
/ 21 августа 2013

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

<a href="@Url.Isolate(u => u.Action("View", "Person"))">View</a>

Подробности реализации в этом сообщении в блоге

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