c# - 在启用 LowercaseUrls 的情况下在路由参数中保留大小写

标签 c# asp.net-mvc asp.net-mvc-4

我在我的 MVC 4 应用程序中使用 routes.LowercaseUrls = true;,它运行良好。但是,参数也会小写,所以如果我有一条像

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

生成的链接

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

也会将 URL 的 {hash} 部分小写,例如如果 ViewBag.MyHash = "aX3F5U" 那么生成的链接将是 /foo/ax3f5u 而不是 /foo/aX3F5U

有没有办法强制 MVC 只将 Controller 和操作部分小写?

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

最佳答案

我认为使用 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);

特定 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(... ) 语法:

小写路由类:

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 而不是 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" }
);

暴露所需的行为。

关于c# - 在启用 LowercaseUrls 的情况下在路由参数中保留大小写,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15387299/

相关文章:

C# 在继承 get 中使用 base 或 this

c# - WPF RichTextBox PreviewKeyDown 和 OnTextChange 事件顺序与普通 TextBox 不同

javascript - 使用匿名函数时的预期标识符

c# - 绑定(bind)到 DependencyProperty 仅适用于 "MyValue",不适用于 "{Binding PropertyHoldingMyValue}"

C# smo 项目程序集未引用错误

css - 在 MVC 元素中隐藏鼠标悬停的超链接

html - ASP.NET MVC View HTML 折叠展开

asp.net-mvc-4 - 我应该为我的 Asp.NET MVC 4 beta 过滤器使用哪个命名空间?

HTML5 : Should I use h 2's or h3' s for content inside of an aside element?

javascript - 从 JavaScript 中获取 cshtml 中的 TextBox-Value