【问题标题】:How can I have lowercase routes in ASP.NET MVC?如何在 ASP.NET MVC 中使用小写路由?
【发布时间】:2010-10-27 02:05:56
【问题描述】:

如何在 ASP.NET MVC 中使用小写字母和下划线(如果可能)?这样我就可以让/dinners/details/2 打电话给DinnersController.Details(2),如果可能的话,/dinners/more_details/2 打电话给DinnersController.MoreDetails(2)

所有这些仍然使用{controller}/{action}/{id} 之类的模式。

【问题讨论】:

  • 由于各种原因,我最终还是手动编写了所有路线,我认为很难避免使用不仅仅是 CRUD 的任何东西。所以我只是用小写的。
  • 使用 Web 表单?去这里:msdn.microsoft.com/en-us/library/…。 (我正在逐渐将我的项目从 Web 表单转换为 MVC,并且在项目中都有)
  • 我很确定您可以默认执行此操作
  • 我不认为你输入小写或大写的路线很重要。

标签: asp.net-mvc url routes case canonical-link


【解决方案1】:

使用 System.Web.Routing 4.5,您可以通过设置 RouteCollection 的 LowercaseUrls 属性来实现这一点:

public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.LowercaseUrls = true;

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );
    }

还假设您出于 SEO 原因执行此操作,您希望将传入的 url 重定向为小写(如本文中的许多链接所述)。

protected void Application_BeginRequest(object sender, EventArgs e)
    {
        //You don't want to redirect on posts, or images/css/js
        bool isGet = HttpContext.Current.Request.RequestType.ToLowerInvariant().Contains("get");
        if (isGet && !HttpContext.Current.Request.Url.AbsolutePath.Contains("."))
        {
            //You don't want to modify URL encoded chars (ex.: %C3%8D that's code to Í accented I) to lowercase, than you need do decode the URL
            string urlLowercase = Request.Url.Scheme + "://" + HttpUtility.UrlDecode(HttpContext.Current.Request.Url.Authority + HttpContext.Current.Request.Url.AbsolutePath);
            //You want to consider accented chars in uppercase check
            if (Regex.IsMatch(urlLowercase, @"[A-Z]") || Regex.IsMatch(urlLowercase, @"[ÀÈÌÒÙÁÉÍÓÚÂÊÎÔÛÃÕÄËÏÖÜÝÑ]"))
            {
                //You don't want to change casing on query strings
                urlLowercase = urlLowercase.ToLower() + HttpContext.Current.Request.Url.Query;

                Response.Clear();
                Response.Status = "301 Moved Permanently";
                Response.AddHeader("Location", urlLowercase);
                Response.End();
            }
        }
    }

【讨论】:

  • 这是迄今为止在 4.0 中最简单的事情。
  • 希望这是在顶部...几乎货物崇拜大量的代码!
  • 很好的答案 :-) 后一个 SEO 部分非常适合 HTTP 模块。
  • @Aaron Sherman Application_BeginRequest 部分应该去哪里?当它在公共类 RouteConfig 内部以及在 if 外部时,它都会给我错误。
  • @richard-mišenčík 将其添加到 Global.asax 文件中
【解决方案2】:

当我想做同样的事情并且工作良好时,这两个教程很有帮助:

http://www.coderjournal.com/2008/03/force-mvc-route-url-lowercase/ http://goneale.com/2008/12/19/lowercase-route-urls-in-aspnet-mvc/

编辑:对于有区域的项目,需要修改GetVirtualPath()方法:

public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
  var lowerCaseValues = new RouteValueDictionary();

  foreach (var v in values)
  {
    switch (v.Key.ToUpperInvariant())
    {
      case "ACTION":
      case "AREA":
      case "CONTROLLER":
        lowerCaseValues.Add(v.Key, ((string)v.Value).ToLowerInvariant());
        break;
      default:
        lowerCaseValues.Add(v.Key.ToLowerInvariant(), v.Value);
        break;
    }
  }
  return base.GetVirtualPath(requestContext, lowerCaseValues);
}

【讨论】:

【解决方案3】:

如果你碰巧用过 ASP.NET Core,你可能应该看看this

将以下行添加到Startup 类的ConfigureServices 方法中。

services.AddRouting(options => options.LowercaseUrls = true);

【讨论】:

【解决方案4】:

如果您使用 UrlHelper 生成链接,您可以简单地将动作和控制器的名称指定为小写:

itemDelete.NavigateUrl = Url.Action("delete", "photos", new { key = item.Key });

结果:/media/photos/delete/64(即使我的控制器和操作是帕斯卡大小写)。

【讨论】:

  • 我认为在一个中心位置进行这项工作是最简单和最标准的解决方案。这和内联 CSS 一样糟糕。 (显然有 15 人使用内联 CSS)。
  • Linux 服务器也是这样吗?
【解决方案5】:

我在Nick Berardi’s Coder Journal 找到了这个,但它没有关于如何实现LowercaseRoute 类的信息。因此,在此处重新发布其他信息。

首先将Route类扩展为LowercaseRoute

public class LowercaseRoute : Route
{
    public LowercaseRoute(string url, IRouteHandler routeHandler)
        : base(url, routeHandler) { }
    public LowercaseRoute(string url, RouteValueDictionary defaults, IRouteHandler routeHandler)
        : base(url, defaults, routeHandler) { }
    public LowercaseRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, IRouteHandler routeHandler)
        : base(url, defaults, constraints, routeHandler) { }
    public LowercaseRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, RouteValueDictionary dataTokens, IRouteHandler routeHandler) : base(url, defaults, constraints, dataTokens, routeHandler) { }
    public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
    {
        VirtualPathData path = base.GetVirtualPath(requestContext, values);

        if (path != null)
            path.VirtualPath = path.VirtualPath.ToLowerInvariant();

        return path;
    }
}

然后修改Global.asax.cs的RegisterRoutes方法

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.Add(new LowercaseRoute("{controller}/{action}/{id}", 
        new RouteValueDictionary(new { controller = "Home", action = "Index", id = "" }), 
        new MvcRouteHandler()));

    //routes.MapRoute(
    //    "Default",                                              // Route name
    //    "{controller}/{action}/{id}",                           // URL with parameters
    //    new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
    //);
}

不过我想知道一种使用 routes.MapRoute 的方法...

【讨论】:

  • GONeale 的文章提供了一个扩展方法,所以你可以写routes.MapRouteLowercase(...,比上面的更好:goneale.wordpress.com/2008/12/19/…
  • GONeale 的整个博客消失了。 Here is another blog entry 具有相似的内容(和相同的扩展方法)。它在减少重复内容的背景下解决了这种情况。
【解决方案6】:

您可以通过将此类作为扩展添加到 RouteCollection 来继续使用 MapRoute 语法:

public static class RouteCollectionExtension
{
    public static Route MapRouteLowerCase(this RouteCollection routes, string name, string url, object defaults)
    {
        return routes.MapRouteLowerCase(name, url, defaults, null);
    }

    public static Route MapRouteLowerCase(this RouteCollection routes, string name, string url, object defaults, object constraints)
    {
        Route route = new LowercaseRoute(url, new MvcRouteHandler())
        {
            Defaults = new RouteValueDictionary(defaults),
            Constraints = new RouteValueDictionary(constraints)
        };

        routes.Add(name, route);

        return route;
    }
}

现在您可以在应用程序的启动中使用“MapRouteLowerCase”而不是“MapRoute”:

    public void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        // Url shortcuts
        routes.MapRouteLowerCase("Home", "", new { controller = "Home", action = "Index" });
        routes.MapRouteLowerCase("Login", "login", new { controller = "Account", action = "Login" });
        routes.MapRouteLowerCase("Logout", "logout", new { controller = "Account", action = "Logout" });

        routes.MapRouteLowerCase(
            "Default",                                              // Route name
            "{controller}/{action}/{id}",                           // URL with parameters
            new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
        );
    }

【讨论】:

  • 对于任何阅读本文的人来说,上面第一个代码 sn-p 中的 LowercaseRoute 类似乎来自 this other answer
【解决方案7】:

这其实有两个答案:

  1. 您已经可以这样做了:路由引擎进行不区分大小写的比较。如果您键入小写的路由,它将被路由到相应的控制器和操作。
  2. 如果您使用生成路由链接的控件(ActionLink、RouteLink 等),除非您覆盖此默认行为,否则它们将生成大小写混合的链接。

不过,下划线只能靠你自己了……

【讨论】:

    【解决方案8】:

    你能使用 ActionName 属性吗?

     [ActionName("more_details")]
     public ActionResult MoreDetails(int? page)
     {
    
     }
    

    我认为大小写无关紧要。 URL 中的 More_Details、more_DETAILS、mOrE_DeTaILs 都将您带到同一个 Controller Action。

    【讨论】:

    • 我没有尝试过——它会让你使用其中一个吗? (“更多细节”或“更多细节”)
    • 跟进,我试过了,它要求你使用指定的名称,所以不,它不允许你处理它。此外,根据您构建控制器操作和视图的方式,您可能需要明确指定视图的名称。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-10-12
    • 1970-01-01
    • 2010-11-11
    • 1970-01-01
    • 1970-01-01
    • 2012-02-02
    相关资源
    最近更新 更多