草庐IT

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

coder 2024-05-23 原文

我在我的 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# - 在启用 LowercaseUrls 的情况下在路由参数中保留大小写的更多相关文章

  1. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

    exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

  2. ruby - 默认情况下使选项为 false - 2

    这是在Ruby中设置默认值的常用方法:classQuietByDefaultdefinitialize(opts={})@verbose=opts[:verbose]endend这是一个容易落入的陷阱:classVerboseNoMatterWhatdefinitialize(opts={})@verbose=opts[:verbose]||trueendend正确的做法是:classVerboseByDefaultdefinitialize(opts={})@verbose=opts.include?(:verbose)?opts[:verbose]:trueendend编写Verb

  3. ruby - RSpec - 使用测试替身作为 block 参数 - 2

    我有一些Ruby代码,如下所示:Something.createdo|x|x.foo=barend我想编写一个测试,它使用double代替block参数x,这样我就可以调用:x_double.should_receive(:foo).with("whatever").这可能吗? 最佳答案 specify'something'dox=doublex.should_receive(:foo=).with("whatever")Something.should_receive(:create).and_yield(x)#callthere

  4. ruby - 如何在 Ruby 中拆分参数字符串 Bash 样式? - 2

    我正在为一个项目制作一个简单的shell,我希望像在Bash中一样解析参数字符串。foobar"helloworld"fooz应该变成:["foo","bar","helloworld","fooz"]等等。到目前为止,我一直在使用CSV::parse_line,将列分隔符设置为""和.compact输出。问题是我现在必须选择是要支持单引号还是双引号。CSV不支持超过一个分隔符。Python有一个名为shlex的模块:>>>shlex.split("Test'helloworld'foo")['Test','helloworld','foo']>>>shlex.split('Test"

  5. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

  6. ruby - 检查方法参数的类型 - 2

    我不确定传递给方法的对象的类型是否正确。我可能会将一个字符串传递给一个只能处理整数的函数。某种运行时保证怎么样?我看不到比以下更好的选择:defsomeFixNumMangler(input)raise"wrongtype:integerrequired"unlessinput.class==FixNumother_stuffend有更好的选择吗? 最佳答案 使用Kernel#Integer在使用之前转换输入的方法。当无法以任何合理的方式将输入转换为整数时,它将引发ArgumentError。defmy_method(number)

  7. ruby-on-rails - 在默认方法参数中使用 .reverse_merge 或 .merge - 2

    两者都可以defsetup(options={})options.reverse_merge:size=>25,:velocity=>10end和defsetup(options={}){:size=>25,:velocity=>10}.merge(options)end在方法的参数中分配默认值。问题是:哪个更好?您更愿意使用哪一个?在性能、代码可读性或其他方面有什么不同吗?编辑:我无意中添加了bang(!)...并不是要询问nobang方法与bang方法之间的区别 最佳答案 我倾向于使用reverse_merge方法:option

  8. ruby - 定义方法参数的条件 - 2

    我有一个只接受一个参数的方法:defmy_method(number)end如果使用number调用方法,我该如何引发错误??通常,我如何定义方法参数的条件?比如我想在调用的时候报错:my_method(1) 最佳答案 您可以添加guard在函数的开头,如果参数无效则引发异常。例如:defmy_method(number)failArgumentError,"Inputshouldbegreaterthanorequalto2"ifnumbereputse.messageend#=>Inputshouldbegreaterthano

  9. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  10. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

随机推荐