c# - validar - Conservar mayúsculas y minúsculas en los parámetros de ruta con LowercaseUrls habilitado
totitlecase c# (4)
Estoy usando routes.LowercaseUrls = true;
en mi aplicación MVC 4 que funciona muy bien. Sin embargo, los parámetros también se mostrarán en minúscula, así que si tengo una ruta como
routes.MapRoute(
name: "MyController",
url: "foo/{hash}/{action}",
defaults: new { controller = "MyController", action = "Details" }
);
El enlace generado con
@Html.ActionLink("my link", "Details", new { hash=ViewBag.MyHash })
también tendrá la {hash}
-parte de la URL en minúscula, por ejemplo, si ViewBag.MyHash = "aX3F5U"
, el enlace generado será /foo/ax3f5u
lugar de /foo/aX3F5U
¿Hay alguna manera de forzar a MVC a que solo ponga en minúscula el controlador y las partes de acción?
Para las versiones anteriores de MVC, el camino a seguir parecía ser implementar una subclase personalizada de Route
, sin embargo, no sé cómo / dónde crear una instancia, ya que la firma de los constructores de ruta es bastante diferente de MapRoute
y estoy esperando que haya una manera más simple.
Aquí hay una manera simple de hacer esto,
public class MyRoute : Route
{
public MyRoute(string url, object defaults): base(url, new RouteValueDictionary(defaults), new MvcRouteHandler())
{
}
public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
if (values["action"] != null)
values["action"] = values["action"].ToString().ToLowerInvariant();
if (values["controller"] != null)
values["controller"] = values["controller"].ToString().ToLowerInvariant();
return base.GetVirtualPath(requestContext, values);
}
}
routes.Add("Default",new MyRoute("{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = MyUrlParameter.Optional }));
Vea esta publicación en el blog para más detalles.
Creo que la solución con una subclase personalizada de Route
será lo suficientemente buena y simple, pero al mismo tiempo un poco fea :)
Puede agregar un CustomRoute
en el método RegisterRoute
de RouteConfig.cs
. Agregue el siguiente código en lugar de routes.MapRoute
var route = new CustomRoute(new Route(
url: "{controller}/{action}/{id}",
defaults: new RouteValueDictionary() {
{ "controller", "Home" },
{ "action", "Index" },
{ "id", UrlParameter.Optional }
},
routeHandler: new MvcRouteHandler()
));
routes.Add(route);
La implementación de CustomRoute
particular puede verse así:
public class CustomRoute : RouteBase
{
private readonly RouteBase route;
public CustomRoute(RouteBase route)
{
this.route = route;
}
public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
values = new RouteValueDictionary(values.Select(v =>
{
return v.Key.Equals("action") || v.Key.Equals("controller")
? new KeyValuePair<String, Object>(v.Key, (v.Value as String).ToLower())
: v;
}).ToDictionary(v => v.Key, v => v.Value));
return route.GetVirtualPath(requestContext, values);
}
public override RouteData GetRouteData(HttpContextBase httpContext)
{
return route.GetRouteData(httpContext);
}
}
Sin embargo, no es una implementación óptima. Un ejemplo completo podría usar una combinación de extensiones en RouteCollection
y un Route
child personalizado para mantenerlo lo más cerca posible de la sintaxis de routes.MapRoute(...)
:
Clase LowRoseRoute:
public class LowercaseRoute : Route
{
public LowercaseRoute(string url, IRouteHandler routeHandler) : base(url, routeHandler) { }
public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
values = new RouteValueDictionary(values.Select(v =>
{
return v.Key.Equals("action") || v.Key.Equals("controller")
? new KeyValuePair<String, Object>(v.Key, (v.Value as String).ToLower())
: v;
}).ToDictionary(v => v.Key, v => v.Value));
return base.GetVirtualPath(requestContext, values);
}
}
Clase RouteCollectionExtensions:
public static class RouteCollectionExtensions
{
[SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId = "2#", Justification = "This is not a regular URL as it may contain special routing characters.")]
public static Route MapLowercaseRoute(this RouteCollection routes, string name, string url)
{
return MapLowercaseRoute(routes, name, url, null /* defaults */, (object)null /* constraints */);
}
[SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId = "2#", Justification = "This is not a regular URL as it may contain special routing characters.")]
public static Route MapLowercaseRoute(this RouteCollection routes, string name, string url, object defaults)
{
return MapLowercaseRoute(routes, name, url, defaults, (object)null /* constraints */);
}
[SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId = "2#", Justification = "This is not a regular URL as it may contain special routing characters.")]
public static Route MapLowercaseRoute(this RouteCollection routes, string name, string url, object defaults, object constraints)
{
return MapLowercaseRoute(routes, name, url, defaults, constraints, null /* namespaces */);
}
[SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId = "2#", Justification = "This is not a regular URL as it may contain special routing characters.")]
public static Route MapLowercaseRoute(this RouteCollection routes, string name, string url, string[] namespaces)
{
return MapLowercaseRoute(routes, name, url, null /* defaults */, null /* constraints */, namespaces);
}
[SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId = "2#", Justification = "This is not a regular URL as it may contain special routing characters.")]
public static Route MapLowercaseRoute(this RouteCollection routes, string name, string url, object defaults, string[] namespaces)
{
return MapLowercaseRoute(routes, name, url, defaults, null /* constraints */, namespaces);
}
[SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId = "2#", Justification = "This is not a regular URL as it may contain special routing characters.")]
public static Route MapLowercaseRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces)
{
if (routes == null)
{
throw new ArgumentNullException("routes");
}
if (url == null)
{
throw new ArgumentNullException("url");
}
Route route = new LowercaseRoute(url, new MvcRouteHandler())
{
Defaults = CreateRouteValueDictionary(defaults),
Constraints = CreateRouteValueDictionary(constraints),
DataTokens = new RouteValueDictionary()
};
if ((namespaces != null) && (namespaces.Length > 0))
{
route.DataTokens["Namespaces"] = namespaces;
}
routes.Add(name, route);
return route;
}
private static RouteValueDictionary CreateRouteValueDictionary(object values)
{
var dictionary = values as IDictionary<string, object>;
if (dictionary != null)
{
return new RouteValueDictionary(dictionary);
}
return new RouteValueDictionary(values);
}
}
Ahora puede usar MapLowercaseRoute
lugar de MapRoute
, por lo que
routes.MapRoute(
name: "MyController",
url: "foo/{hash}/{action}",
defaults: new { controller = "MyController", action = "Details" }
);
simplemente se convierte
routes.MapLowercaseRoute(
name: "MyController",
url: "foo/{hash}/{action}",
defaults: new { controller = "MyController", action = "Details" }
);
exponiendo el comportamiento deseado.
Es simple como 1.2.3,
mira este ejemplo
routes.MapRouteLowercase( // changed from routes.MapRoute
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Es sencillo descargarlo e instalarlo a través de Nuget, lo uso. PM> Install-Package LowercaseRoutesMVC
Si RouteCollection.NormalizeVirtualPath
método privado RouteCollection.NormalizeVirtualPath
, verá que simplemente utiliza virtualPath.ToLowerInvariant()
. Entonces no hay forma de manejar eso. Incluso si creas tu propia ruta, será en minúscula.
Pero lo que puedes hacer es agregar hash después del signo ''#'', es decir, "foo/{action}/#{hash}"
. No lo he intentado, pero debería funcionar. Solo mira la implementación de NormalizeVirtualPath
.