13

Tengo una aplicación ASP.NET MVC 3 donde los usuarios pueden publicar sugerencias en la línea de "bla bla sería mejor si yada yada yada". Para la página de detalles sugerencia he definido un buen SEO ruta de la siguiente manera:Ruta ASP.NET MVC que falla. ¿Es esto un error o caso de esquina?

routes.MapRoute(null, "suggestion/{id}/{it}/would-be-better-if-{if}", 
    new { controller = "suggestion", action = "details" }); 

Como se puede ver Quiero que el "Sería mejor si" la parte que se determinen.

Esta ruta funciona perfectamente para cualquier sugerencia antigua y genera enlaces como suggestion/5/this-site/would-be-better-if-it-had-a-iphone-application, y al hacer clic en el enlace realmente solicita la página de detalles adecuada.

Un amigo mío, que irónicamente pasa a ser un probador, ha logrado, involuntariamente, publicar una sugerencia que realmente rompe la ruta: "Este sitio sería mejor si 'sería mejor si' siempre estaba alineado en el medio ".
El enlace generado para esta sugerencia es /suggestion/84/this-site/would-be-better-if-would-be-better-if-was-always-alligned-in-the-middle.

He intentado Phil Haack's Routing Debugger y he confirmado que la ruta funcionará realmente hasta suggestion/84/this-site/would-be-better-if-would-be-better-if-, por lo que el segundo "mejor-sería-si" es realmente aceptado; agregar algo después de eso hará que la URL no coincida con ninguna ruta (gracias a Omar -ver comentarios- para obtener ayuda).


Por favor tener en cuenta que Realmente no quiero cambiar la definición de la ruta ya que creo que es tan bueno como puedo manejar para este caso, SEO se refiere.

Así que, ¿cómo es que tener texto igual a la parte fija de la ruta impide el enlace de la concordancia de la ruta? ¿por qué es la ruta de la ruptura?

En realidad, estoy más interesado en el por qué, ya que creo que entender el por qué dará lugar a una solución o al menos una comprensión adecuada de un problema bastante interesante.

+2

Esto es muy interesante. No estoy seguro de por qué está sucediendo, pero si desea una solución temporal, reemplace '- {if}' con '/ {if}'. Supongo que ASP.NET MVC trata '/' diferente de otros caracteres. – Omar

+1

Algunas pruebas revelaron que la ruta 'sugerencia/84/this-site/would-be-better-if-would-be-better-if-' funciona; solo después de que tenga algo después del último '-' se rompe. – Omar

+0

@Omar - I * really * no quiero cambiar la ruta, aunque la solución propuesta es bastante aceptable.En cuanto a tu segundo comentario, gracias, lo extrañé por completo ... Esto lo hace aún más curioso si me preguntas. –

Respuesta

5

no estoy seguro de por qué se comporta de esta manera, pero se puede usar algo como esto:

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); 
    } 
} 

Uso:

routes.Add(new ComplexRoute(
    "suggestion/{id}/{it}/{if}", 
    new { controller = "suggestion", action = "details" }, 
    new { @if = new StartsWithRouteRule("would-be-better-if-") })); 
+0

áš - Esto podría funcionar (no lo he probado aún), pero estoy realmente muy interesado en * por qué * es que la ruta se rompe. –

+0

Me inclino a aceptar que la razón por la que se rompe es un error. ¿Has probado esto con alguien en el equipo de MVC? –

+0

@Matt - En realidad no lo he hecho, pero creo que lo haré de inmediato. Gracias por el consejo. –