Окружающие значения в маршрутизации mvc2.net - PullRequest
5 голосов
/ 13 августа 2010

У меня есть следующие два маршрута, зарегистрированные в моем global.asax файле

routes.MapRoute(
    "strict",
    "{controller}.mvc/{docid}/{action}/{id}",
    new { action = "Index", id = "", docid = "" },
    new { docid = @"\d+"}
);
routes.MapRoute(
    "default",
    "{controller}.mvc/{action}/{id}",
    new { action = "Index", id = "" },
    new { docConstraint = new DocumentConstraint() }
);

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

 <ul id="globalnav" class = "t-reset t-tabstrip-items">
     <li class="bar" id = "dashboard">
         <%=Html.ActionLink("dash.board", "Index", pck.Controller,  new{docid =string.Empty,id = pck.PkgID }, new { @class = "here" })%>
     </li>
     <%  
         foreach (var md in pck.sysModules)
         {
     %>
     <li class="<%=liClass%>">
         <%=Html.ActionLink(md.ModuleName, md.ActionName, pck.Controller, new { docid = md.DocumentID}, new { @class = cls })%>
     </li>
     <%
         }
     %>
 </ul>

Теперь мой стартовый адрес localhost/oa.mvc/index/11 явно соответствует 2-му маршруту.Но когда я захожу на любую страницу, которая сопоставлена ​​с первым маршрутом, а затем возвращаюсь по ссылке dash.board, она показывает мне localhost/oa.mvc/7/index/11, где 7 равно docid и выбрано из предыдущего URL.

Я понимаю, что мой метод действия после docid, и его изменение не очистит docid.

Мой вопрос здесь, могу ли я удалить docid в этом сценарии без изменения маршрута?

Ответы [ 6 ]

4 голосов
/ 24 февраля 2011

Моя маршрутизация определяется следующим образом:

routes.MapRoute(
    "Planning",
    "Plans/{plan}/{controller}/{action}/{identifier}",
    new { controller = "General", action = "Planning", identifier = UrlParameter.Optional },
    new { plan = @"^\d+$" }
);

// default application route
routes.MapRoute(
    "Default",
    "{controller}/{action}/{identifier}",
    new {
        controller = "General",
        action = "Summary",
        identifier = UrlParameter.Optional,
        plan = string.Empty // mind this default !!!
    }
);

Это очень похоже на то, что вы используете. Но помните мой маршрут по умолчанию, где я определяю значения по умолчанию. Несмотря на то, что мой маршрут по умолчанию не определяет значение маршрута plan, я все равно установил его на string.Empty. Поэтому, когда я использую Html.ActionLink() или Url.Action() и хочу удалить plan из URL, я называю это обычным способом:

Url.Action("Action", "Controller", new { plan = string.Empty });

И план больше не включается в строку запроса URL. Попробуйте сами, это может сработать.

4 голосов
/ 22 августа 2010

У меня та же проблема "не очищения" значения ...

Я вошел в исходный код, и я не понимаю причину того, что сегмент был прокомментирован как: // Добавить все текущие значения, которых вообще нет в URL

@ System\Web\Routing\ParsedRoute.cs, public BoundUrl Bind(RouteValueDictionary currentValues, RouteValueDictionary values, RouteValueDictionary defaultValues, RouteValueDictionary constraints) метод из строки 91 в строку 100

Хотя процесс очистки корректно обрабатывается в методах, предшествующих шагам, этот код "повторно вводит" нежелательный параметр в словарь acceptValues!?

2 голосов
/ 18 февраля 2011

Это такая неприятная проблема, и я бы рискнул сказать, что это даже ошибка в ASP.Net MVC. К счастью, это легко исправить с помощью ActionFilters. Если вы используете MVC3, то я бы просто поместил это как глобальный атрибут, чтобы очистить окружающие значения. Я сделал этот атрибут дискриминационным, но вы можете изменить его, чтобы очистить все атрибуты.

Предполагается, что к моменту выполнения Результата (по вашему мнению) вы уже явно указали все свои ActionLinks и Form Actions. Таким образом, это будет выполнено до того, как они (ссылки) будут оценены, предоставляя вам новую основу для их генерации.

public class ClearAmbientRouteValuesAttribute : ActionFilterAttribute 
{
    private readonly string[] _keys;

    public ClearAmbientRouteValuesAttribute(params string [] keys)
    {
        if (keys == null)
            _keys = new string[0];

        _keys = keys;
    }

    public override void OnResultExecuting(ResultExecutingContext filterContext)
    {
        foreach (var key in _keys) {
            // Why are you sticking around!!!
            filterContext.RequestContext.RouteData.Values.Remove(key);        
        }
    }
}

// Inside your Global.asax
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
    filters.Add(new HandleErrorAttribute());
    filters.Add(new ClearAmbientRouteValuesAttribute("format"));
}

Надеюсь, это кому-то поможет, потому что это, безусловно, помогло мне. Спасибо, что задали этот вопрос.

2 голосов
/ 23 августа 2010

Мухаммед, я предлагаю что-то вроде этого: (написано 5 мин. назад, не тестировалось в производстве)

public static class MyHtmlHelperExtensions {

    public static MvcHtmlString FixActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, object routeValues, object htmlAttributes) {
        var linkRvd = new RouteValueDictionary(routeValues);
        var contextRvd = htmlHelper.ViewContext.RouteData.Values;
        var contextRemovedRvd = new RouteValueDictionary();

        // remove clearing route values from current context
        foreach (var rv in linkRvd) {
            if (string.IsNullOrEmpty((string)rv.Value) && contextRvd.ContainsKey(rv.Key)) {
                contextRemovedRvd.Add(rv.Key, contextRvd[rv.Key]);
                contextRvd.Remove(rv.Key);
            }
        }

        // call ActionLink with modified context
        var htmlString = htmlHelper.ActionLink(linkText, actionName, controllerName, routeValues, htmlAttributes);

        // restore context
        foreach (var rv in contextRemovedRvd) {
            contextRvd.Add(rv.Key, rv.Value);
        }

        return htmlString;
    }
}
0 голосов
/ 22 декабря 2011

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

Выдержки из Apress Pro ASP.Net.MVC 3 Framework:

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

  • Ни одно из значений, которые мы указали для переменных сегмента, может не совпадать с переменные только по умолчанию, определенные в маршруте. Это переменные, для которых по умолчанию значения были предоставлены, но которые не встречаются в шаблоне URL. За Например, в этом определении маршрута myVar является переменной только по умолчанию:

    rout.MapRoute ("MyRoute", "{controller} / {action}", new {myVar = "true"});

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

  • Значения всех переменных сегмента должны удовлетворять ограничениям маршрута. Увидеть раздел «Ограничение маршрутов» ранее в этой главе для примеров различных виды ограничений.

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

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

routes.MapRoute(null, "receptionists/faq/{page}", new { controller = "Receptionist", action = "Faq", page = 1, category = (Object)null }, new { page = @"^\d+$" });

routes.MapRoute(null, "receptionists/faq/{category}/{page}", new { controller = "Receptionist", action = "Faq", page = 1 }, new { category = @"^\D+$", page = @"^\d+$" });

Для ссылок категории

@Html.ActionLink("All", "Faq", new { page = 1 })

@foreach (var category in Model.Categories)
{
@Html.ActionLink(category.DisplayName, "faq", new { category = category.DisplayName.ToLower(), page = 1 })
}

Для ссылок на страницы

@for (var p = 1; p <= Model.TotalPages; p++)
{
@Html.ActionLink(p.ToString(), "Faq", new { page = p, category = Model.CurrentCategory})
}
0 голосов
/ 16 августа 2010

В этом конкретном сценарии у меня есть две рекомендации:

  1. Использовать именованные маршруты. Первый параметр метода MapRoute - это имя. Для генерации ссылок используйте Html.RouteLink() (и другие подобные API). Таким образом, вы всегда будете выбирать точный маршрут, который вам нужен, и вам никогда не придется задаваться вопросом, что будет выбрано.

  2. Если вы все еще хотите использовать Html.ActionLink(), тогда явно установите docid="", чтобы очистить его значение.

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