如何在ASP.NET MVC中使用小写路由?


145

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

所有这一切仍在使用诸如的模式{controller}/{action}/{id}


由于各种原因,我最终还是手动编写了所有路线,并且我认为很难避免使用不只是CRUD的方法来做到这一点。所以我只是用小写写的。
pupeno

使用Web表单?转到此处:msdn.microsoft.com/en-us/library/…。(我正在将我的项目逐渐从Web表单转换为MVC,并且都包含在该项目中)
Jess

我非常确定您可以默认执行此操作

我不认为这是重要的,如果您以小写或大写形式输入路由。

Answers:


238

使用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(".") == false)    
  {
     string lowercaseURL = (Request.Url.Scheme + "://" + HttpContext.Current.Request.Url.Authority + HttpContext.Current.Request.Url.AbsolutePath);
     if (Regex.IsMatch(lowercaseURL, @"[A-Z]"))
     {
      //You don't want to change casing on query strings
      lowercaseURL = lowercaseURL.ToLower() + HttpContext.Current.Request.Url.Query;

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

4
到目前为止,这是4.0版中最简单的操作。
保罗·特纳

1
希望这是最重要的...几乎要花很多功夫!
akatakritos

2
好的答案:-)后面的SEO部分非常适合HTTP模块。
大卫·柯克兰

1
@Aaron Sherman应该将Application_BeginRequest部分放在哪里?当它在公共类RouteConfig内时以及在if之外时,都给我错误。
RichardMišenčík2015年

1
@richard-mišenčík将其添加到Global.asax文件中
ITmeze 2015年

44

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

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


4
@Derek-不,使用Area的教程会崩溃。经过三天的尝试...我找到了一个更好的解决方案,这里有一个名为Attribute Routing的库。解决了问题,使生活更加轻松。philliphaydon.com/2011/08/…–
Phill

6
对于mvc 4,有一个使用属性路由的更好的解决方案。LowercaseUrls= true; 有关dhuvelle.com/2012/11/tips-for-aspnet-mvc-4-lowercase-urls.html的
Marc

4
@GONeale您的URL发生了什么?现在第二个链接已死!虽然让我笑了,但标题是“ Internet上最好的Ale网站”
路加福音

2
@chteuchteu那个链接对我不起作用,但是这个对我有用。
chux x


21

如果使用UrlHelper生成链接,则只需将操作和控制器的名称指定为小写即可:

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

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


16
我认为在一个中心位置进行这项工作是最简单,最标准的解决方案。这和内联CSS一样糟糕。(显然有15个人使用内联CSS)。
松饼人2012年

Linux服务器也是如此吗?
QMaster

15

我是在Nick Berardi的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;
    }
}

然后修改RegisterRoutesGlobal.asax.cs 的方法

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/...
德鲁诺克斯

1
GONeale的整个博客都消失了。这是另一个内容相似(扩展方法相同)的博客条目。它在减少重复内容的情况下解决了这种情况。
patridge

11

您可以通过添加此类作为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
        );
    }

对于阅读此书的任何人,LowercaseRoute上面第一个代码段中的课程似乎都来自于另一个答案
chue x

6

这实际上有两个答案:

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

不过,下划线是您自己的事...


2

您可以使用ActionName属性吗?

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

 }

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


我没有尝试过-它可以让您使用其中任何一个吗?(“ moredetails”或“ more_details”)
GalacticCowboy

为了进行跟进,我尝试了它,它要求您使用指定的名称,所以不,它不允许您以任何方式处理它。另外,根据构造控制器动作和视图的方式,可能需要显式指定视图的名称。
GalacticCowboy
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.