Ошибка в пути ASP.NET MVC. Это ошибка или угловой случай?
У меня есть приложение ASP.NET MVC 3, в котором пользователи могут публиковать предложения по строкам "bla bla было бы лучше, если yada yada yada".
На странице подробных предложений я определил хороший дружественный маршрут для SEO следующим образом:
routes.MapRoute(null, "suggestion/{id}/{it}/would-be-better-if-{if}",
new { controller = "suggestion", action = "details" });
Как вы можете видеть, я хочу, чтобы часть "была бы лучше, если" была исправлена.
Этот маршрут отлично работает для любого старого предложения и создает такие ссылки, как suggestion/5/this-site/would-be-better-if-it-had-a-iphone-application
, и нажатие на ссылку действительно запрашивает соответствующую страницу подробностей.
Друг мой, который по иронии судьбы оказался тестером, сумел, невольно, опубликовать предложение, которое действительно нарушает маршрут: "Этот сайт был бы лучше, если бы было" лучше, если бы "всегда выравнивался в середине".
Ссылка, сгенерированная для этого предложения,
/suggestion/84/this-site/would-be-better-if-would-be-better-if-was-always-alligned-in-the-middle
.
Я пробовал Phil Haack Routing Debugger и подтвердил, что маршрут будет работать до suggestion/84/this-site/would-be-better-if-would-be-better-if-
, поэтому второй "быть лучше - если" фактически принято"; добавление чего-либо после этого на самом деле приведет к тому, что URL-адрес не будет соответствовать ни одному маршруту (спасибо Omar -see comments- за помощью).
Пожалуйста, имейте в виду, что я действительно не хочу изменять определение маршрута, так как я думаю, что это так хорошо, как я могу справиться в этом случае, SEO-мудрый.
Итак, , как, имеющий текст, равный фиксированной части маршрута, препятствует сопоставлению линии с маршрутом? почему является нарушение маршрута?
На самом деле я больше заинтересован в почему, поскольку я считаю, что понимание того, почему приведет к решению или по крайней мере правильному пониманию довольно интересной проблемы.
Ответы
Ответ 1
Это выглядит как обман маршрутизации ASP.NET: литеральный подсегмент между токенами и значениями маршрута с символом из литерального подсегмента, который является гораздо более простая версия ошибки. Я бы рекомендовал закрыть это в пользу этого.
Я ответил на этот вопрос.
Ответ 2
Я не уверен, почему он ведет себя таким образом, но вы можете использовать что-то вроде этого:
public interface IRouteRule
{
object ProcessIncoming(object value);
object ProcessOutgoing(object value);
}
public class StartsWithRouteRule : IRouteRule
{
public StartsWithRouteRule(string value)
{
Value = value;
}
public string Value { get; protected set; }
public object ProcessIncoming(object value)
{
var result = value as string;
if (result == null)
return null;
if (!result.StartsWith(Value))
return null;
return result.Substring(Value.Length);
}
public object ProcessOutgoing(object value)
{
var result = value as string;
if (result == null)
return null;
return Value + result;
}
}
public class ComplexRoute : Route
{
public ComplexRoute(string url, object defaults, object rules)
: this(url, new RouteValueDictionary(defaults), rules)
{ }
public ComplexRoute(string url, RouteValueDictionary defaults, object rules)
: base(url, defaults, new MvcRouteHandler())
{
Rules = new Dictionary<string, IRouteRule>();
foreach (var pair in new RouteValueDictionary(rules))
Rules.Add(pair.Key, (IRouteRule)pair.Value);
}
public Dictionary<string, IRouteRule> Rules { get; protected set; }
public override RouteData GetRouteData(HttpContextBase httpContext)
{
var result = base.GetRouteData(httpContext);
if (result == null)
return null;
foreach (var pair in Rules)
{
var currentValue = result.Values[pair.Key];
if (currentValue == null)
return null;
var value = pair.Value.ProcessIncoming(currentValue);
if (value == null)
return null;
result.Values[pair.Key] = value;
}
return result;
}
public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
values = new RouteValueDictionary(values);
foreach (var pair in Rules)
{
var currentValue = values[pair.Key];
if (currentValue == null)
return null;
var value = pair.Value.ProcessOutgoing(currentValue);
if (value == null)
return null;
values[pair.Key] = value;
}
return base.GetVirtualPath(requestContext, values);
}
}
Использование:
routes.Add(new ComplexRoute(
"suggestion/{id}/{it}/{if}",
new { controller = "suggestion", action = "details" },
new { @if = new StartsWithRouteRule("would-be-better-if-") }));