ฉันจะมีเส้นทางตัวพิมพ์เล็กใน 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

ใช้เว็บฟอร์มหรือไม่ ไปที่นี่: msdn.microsoft.com/en-us/library/… . (ผมค่อยๆแปลงโครงการของฉันจากรูปแบบเว็บ MVC และมีทั้งในโครงการ)
เจส

ฉันค่อนข้างแน่ใจว่าคุณสามารถทำสิ่งนี้เป็นค่าเริ่มต้น

ฉันไม่คิดว่ามันสำคัญถ้าคุณพิมพ์เส้นทางในกรณีที่ต่ำกว่าหรือบน

คำตอบ:


238

ด้วย System.Web.Routing 4.5 คุณสามารถใช้สิ่งนี้ได้โดยการตั้งค่าคุณสมบัติ LowercaseUrls ของ RouteCollection:

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 และเมื่ออยู่นอกหาก
Richard Mišenčík

1
@ richard-mišenčíkเพิ่มลงในไฟล์ Global.asax
ITmeze

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

9
ลิงก์ GONeale เปลี่ยนไป; URL หายไป
Daniel Liuzzi

4
@Derek - ไม่บทเรียนจะพังเมื่อใช้พื้นที่ หลังจากพยายามทุกอย่างเป็นเวลา 3 วัน ... ฉันพบวิธีแก้ปัญหาที่ดีกว่ามีห้องสมุดที่เรียกว่าแอตทริบิวต์เส้นทาง แก้ปัญหาและทำให้ชีวิตง่ายขึ้นมาก philliphaydon.com/2011/08/…
Phill

6
สำหรับ mvc 4 มีวิธีแก้ปัญหาที่ดีกว่าโดยใช้เส้นทางคุณสมบัติLowercaseUrls = true ข้อมูลเพิ่มเติมเกี่ยวกับdhuvelle.com/2012/11/tips-for-aspnet-mvc-4-lowercase-urls.html
Marc Cals

4
@GONeale เกิดอะไรขึ้นกับ URL ของคุณ ลิงค์ที่สองตอนนี้ตายแล้ว! ทำให้ฉันหัวเราะแม้ว่าชื่อจะเป็น " เว็บไซต์Gone Ale ที่ดีที่สุดบนอินเทอร์เน็ต"
ลุค

2
@chteuchteu ลิงก์นั้นใช้ไม่ได้สำหรับฉัน แต่อันนี้ใช้ได้
chue x

22

หากคุณเกิดขึ้นที่จะใช้ ASP.NET หลักคุณอาจจะมีลักษณะที่นี้ :

เพิ่มบรรทัดต่อไปนี้เป็นConfigureServicesวิธีการStartupเรียน

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

1
เหมือนกันสำหรับ Core 2.0 นอกจากนี้ที่stackoverflow.com/a/45777372/195755
yzorg

21

หากคุณใช้ UrlHelper เพื่อสร้างลิงค์คุณสามารถระบุชื่อของการกระทำและตัวควบคุมเป็นตัวพิมพ์เล็ก:

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

ผลลัพธ์ใน: / media / photos / delete / 64 (แม้ว่าคอนโทรลเลอร์และแอ็คชั่นของฉันเป็นตัวอักษรปาสกาล)


16
ฉันคิดว่าการทำงานนี้ในที่ตั้งศูนย์กลางเดียวเป็นวิธีที่ง่ายและได้มาตรฐานที่สุด นี่เป็นสิ่งที่ไม่ดีเท่ากับ CSS แบบอินไลน์ (เห็นได้ชัดว่า 15 คนใช้ CSS แบบอินไลน์)
ผู้ชายมัฟฟิน

เป็นความจริงสำหรับเซิร์ฟเวอร์ Linux ด้วยหรือไม่
QMaster

15

ฉันพบสิ่งนี้ในCoder Journal ของ Nick Berardiแต่ไม่มีข้อมูลเกี่ยวกับวิธีการใช้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;
    }
}

จากนั้นปรับเปลี่ยนRegisterRoutesวิธีการของ Global.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
    //);
}

อย่างไรก็ตามฉันต้องการทราบวิธีใช้เส้นทาง MapRoute ...


บทความของ GONeale นำเสนอวิธีการขยายเพื่อให้คุณสามารถเขียนroutes.MapRouteLowercase(...ได้ดีกว่าข้างบน: goneale.wordpress.com/2008/12/19/…
Drew Noakes

1
บล็อกทั้งหมดของ GONeale หายไป นี่คือรายการบล็อกอื่นที่มีเนื้อหาคล้ายกัน (และวิธีการขยายเดียวกัน) มันเน้นสถานการณ์นี้ในบริบทของการลดเนื้อหาที่ซ้ำกัน
patridge

11

คุณสามารถใช้ไวยากรณ์ MapRoute ต่อไปได้โดยเพิ่มคลาสนี้เป็นส่วนขยายใน RouteCollection:

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)
 {

 }

ฉันไม่คิดว่าเป็นเรื่องสำคัญ More_Details, more_DETAILS, mOrE_DeTaILs ใน URL ทั้งหมดจะนำคุณไปสู่การดำเนินการควบคุมเดียวกัน


ฉันไม่ได้ลอง - จะให้คุณใช้อันใดอันหนึ่งหรือไม่ ("moredetails" หรือ "more_details")
GalacticCowboy

ในการติดตามฉันลองใช้และต้องการให้คุณใช้ชื่อที่ระบุดังนั้นไม่จะไม่อนุญาตให้คุณจัดการด้วยวิธีใดวิธีหนึ่ง นอกจากนี้ขึ้นอยู่กับว่าคุณสร้างแอคชั่นและมุมมองคอนโทรลเลอร์ของคุณอย่างไรคุณอาจต้องระบุชื่อของมุมมองอย่างชัดเจน
GalacticCowboy
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.