2013-03-13 39 views
14

我在我的MVC 4应用程序中使用routes.LowercaseUrls = true;,该应用程序运行良好。然而,参数也将获得小写,所以如果我有像在启用了LowercaseUrls的路由参数中保留大小写

routes.MapRoute(
    name: "MyController", 
    url: "foo/{hash}/{action}", 
    defaults: new { controller = "MyController", action = "Details" } 
); 

@Html.ActionLink("my link", "Details", new { hash=ViewBag.MyHash }) 

生成的链接的路线将有{hash} -part小写以及URL的,例如,如果ViewBag.MyHash = "aX3F5U"那么生成的链接将是/foo/ax3f5u而不是/foo/aX3F5U

有没有办法强制MVC只控制器和动作部分小写?

对于旧版本的MVC的,要走的路似乎是落实Route自定义子类,但我不知道如何/在哪里实例化,因为路线构造函数的签名是MapRoute完全不同我希望有一个更简单的方法。

+0

你可以添加一个你想要得到的路线的例子吗? – IamStalker 2013-03-16 09:44:24

+0

增加了一个例子 – mensi 2013-03-16 17:20:56

回答

2

我想用Route自定义子类的解决方案将是足够的,简单的好,但在同一时间有点难看:)

您可以在RouteConfig.csRegisterRoute方法添加CustomRoute。添加以下代码,而不是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); 

Implementaion特别CustomRoute可能看起来像这样:

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

但是它不是一个最优实现。一个完整的例子可以使用扩展相结合,在RouteCollection和一个自定义Route孩子保持尽可能接近原来的routes.MapRoute(...)语法:

LowercaseRoute类:

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

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

您现在可以使用MapLowercaseRoute inste的MapRoute广告,因此

routes.MapRoute(
    name: "MyController", 
    url: "foo/{hash}/{action}", 
    defaults: new { controller = "MyController", action = "Details" } 
); 

简单地变为

routes.MapLowercaseRoute(
    name: "MyController", 
    url: "foo/{hash}/{action}", 
    defaults: new { controller = "MyController", action = "Details" } 
); 

暴露所需的行为。

+0

是否有使用组合而不是继承的特定原因? – mensi 2013-03-17 10:30:40

+0

我觉得在这个特例中,没有。但我相信,构图提供了更高的灵活性,当然它有点主观:) – user20140268 2013-03-17 11:03:48

+1

我扩展了你的答案,包括我的解决方案,正如[Jeff Atwood on meta]建议的那样(http://meta.stackexchange.com/questions/27254 /当解决方案是基于另一个答案时最好的方式来授予信用) – mensi 2013-03-17 14:06:04

-1

很简单1.2.3,

看看这个例子

routes.MapRouteLowercase(// changed from routes.MapRoute 
     "Default", 
     "{controller}/{action}/{id}", 
     new { controller = "Home", action = "Index", id = UrlParameter.Optional } 
    ); 

它通过的NuGet是简单的下载和安装它,我用它。 PM> Install-Package LowercaseRoutesMVC

http://lowercaseroutesmvc.codeplex.com/

+0

看看源代码,它似乎也只是将路径转换为小写... – mensi 2013-03-17 10:32:59

+0

Yeap只是下载LowerCaseRoutesMvc就是这样。 – IamStalker 2013-03-17 12:00:42

0

如果你看一下私人RouteCollection.NormalizeVirtualPath方法,你会看到,它只是使用virtualPath.ToLowerInvariant()。所以没有办法处理。即使你创建自己的路线,它也会被缩小。

但是你可以做的是在'#'符号后加上散列,即"foo/{action}/#{hash}"。我没有 尝试过,但它应该工作。只要看看NormalizeVirtualPath的实现。

+0

不起作用(生成404),你在哪里找到'System.Web.Routing'的源代码? – mensi 2013-03-17 10:27:50

+0

我用Resharper看了一下。我不确定我是否可以将其粘贴到此处。您可以使用JetBrains中的dotPeek - 它不是免费的。试试hash作为查询参数,即'foo /?myhash = aX3F5U'。我相信这会起作用。 – 2013-03-17 10:51:50

+0

你可能会得到404,因为你也应该改变你的路线以了解新的url模式:''foo/{action}“' – 2013-03-17 11:01:02

2

这里有一个简单的方法来做到这一点,

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

this blog post查看详细。