Bagaimana saya bisa memiliki rute huruf kecil di ASP.NET MVC?

145

Bagaimana saya bisa menggunakan huruf kecil, plus garis bawah jika mungkin, di ASP.NET MVC? Jadi saya harus /dinners/details/2menelepon DinnersController.Details(2)dan, jika mungkin, /dinners/more_details/2menelepon DinnersController.MoreDetails(2)?

Selama ini masih menggunakan pola suka {controller}/{action}/{id}.

J. Pablo Fernández
sumber
Saya akhirnya menulis semua rute saya secara manual karena berbagai alasan dan saya pikir sulit untuk menghindari melakukan itu dengan apa pun yang bukan hanya CRUD. Jadi saya hanya menulisnya dalam huruf kecil.
pupeno
Menggunakan Formulir Web ? Buka di sini: msdn.microsoft.com/en-us/library/… . (Saya secara bertahap mengubah proyek saya dari formulir web ke MVC dan memiliki keduanya dalam proyek ini)
Jess
saya cukup yakin Anda dapat melakukan ini sebagai default
saya tidak berpikir itu penting jika Anda mengetikkan rute dalam huruf besar atau kecil.

Jawaban:

238

Dengan System.Web.Routing 4.5 Anda dapat menerapkan ini secara langsung dengan mengatur properti LowercaseUrls dari 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 }
        );
    }

Juga dengan asumsi Anda melakukan ini karena alasan SEO Anda ingin mengarahkan url yang masuk ke huruf kecil (seperti yang dikatakan dalam banyak tautan di artikel ini).

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();
    }
 }
}
Aaron Sherman
sumber
4
Sejauh ini, ini adalah hal paling sederhana yang dapat dilakukan di 4.0.
Paul Turner
1
Berharap ini ada di puncak ... Hampir kargo banyak kode!
akatakritos
2
Jawaban bagus :-) Bagian SEO terakhir sangat cocok dengan modul HTTP.
David Kirkland
1
@ Harun Sherman Di mana bagian Application_BeginRequest disuruh pergi? Ini memberi saya kesalahan ketika itu di dalam kelas publik RouteConfig dan juga ketika di luarnya jika.
Richard Mišenčík
1
@ richard-mišenčík menambahkannya ke file Global.asax
ITmeze
44

Dua tutorial ini membantu ketika saya ingin melakukan hal yang sama dan bekerja dengan baik:

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

EDIT: Untuk proyek-proyek dengan area, Anda perlu memodifikasi metode 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);
}
Derek Lawless
sumber
9
Tautan GONeale telah berubah; URL sekarang goneale.com/2008/12/19/lowercase-route-urls-in-aspnet-mvc
Daniel Liuzzi
4
@ Serek - Tidak, tutorialnya mogok saat menggunakan Area's. Setelah 3 hari mencoba SEMUA ... Saya menemukan solusi yang lebih baik, ada perpustakaan yang disebut Routing Atribut. Memecahkan masalah dan membuat hidup jauh lebih mudah. philliphaydon.com/2011/08/...
Phill
6
Untuk mvc 4 ada solusi yang lebih baik menggunakan rute properti.LowercaseUrls = true; Info lebih lanjut tentang dhuvelle.com/2012/11/tips-for-aspnet-mvc-4-lowercase-urls.html
Marc Cals
4
@GONeale Apa yang terjadi pada URL Anda? Tautan kedua sudah mati sekarang! Membuat saya tertawa, judulnya adalah "Situs Gone Ale Terbaik di Internet"
Luke
2
@chteuchteu tautan itu tidak berfungsi untuk saya, tetapi yang ini berhasil.
chue x
22

Jika Anda kebetulan menggunakan ASP.NET Core, Anda mungkin harus melihat ini :

Tambahkan baris berikut ke ConfigureServicesmetode Startupkelas.

services.AddRouting(options => options.LowercaseUrls = true);
Ebrahim Byagowi
sumber
1
Sama untuk Core 2.0. Juga di stackoverflow.com/a/45777372/195755
yzorg
21

Jika Anda menggunakan UrlHelper untuk menghasilkan tautan, Anda cukup menentukan nama tindakan dan pengontrol sebagai huruf kecil:

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

Hasil dalam: / media / foto / delete / 64 (meskipun controller dan action saya adalah huruf pascal).

Mat
sumber
16
Saya pikir melakukan pekerjaan ini di satu lokasi pusat adalah solusi termudah dan paling standar. Ini sama buruknya dengan CSS inline. (Rupanya 15 orang menggunakan CSS sebaris).
The Muffin Man
Apakah benar untuk server Linux juga?
QMaster
15

Saya menemukan ini di Coder Journal Nick Berardi , tetapi tidak memiliki informasi tentang cara mengimplementasikannyaLowercaseRoute kelas. Karenanya reposting di sini dengan informasi tambahan.

Pertama memperluas Routekelas keLowercaseRoute

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

Kemudian modifikasi RegisterRoutesmetode 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
    //);
}

Namun saya ingin tahu cara menggunakan rute. Peta ...

John Oxley
sumber
Artikel GONeale menyediakan metode ekstensi sehingga Anda dapat menulis routes.MapRouteLowercase(...mana yang lebih bagus daripada yang di atas: goneale.wordpress.com/2008/12/19/…
Drew Noakes
1
Seluruh blog GONeale menghilang. Ini adalah entri blog lain dengan konten yang serupa (dan metode ekstensi yang sama). Ini mengatasi situasi ini dalam konteks mengurangi duplikat konten.
patridge
11

Anda dapat terus menggunakan sintaks MapRoute dengan menambahkan kelas ini sebagai ekstensi ke 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;
    }
}

Sekarang Anda dapat menggunakan startup "MapRouteLowerCase" aplikasi Anda alih-alih "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
        );
    }
Markus Wolters
sumber
Bagi siapa pun yang membaca ini, LowercaseRoutekelas dalam cuplikan kode pertama di atas tampaknya berasal dari jawaban lain ini
chue x
6

Ini sebenarnya memiliki dua jawaban:

  1. Anda sudah dapat melakukan ini: mesin rute melakukan perbandingan case-insensitive. Jika Anda mengetik rute huruf kecil, rute akan dialihkan ke pengontrol dan tindakan yang sesuai.
  2. Jika Anda menggunakan kontrol yang menghasilkan tautan rute (ActionLink, RouteLink, dll.) Mereka akan menghasilkan tautan kasus campuran kecuali Anda mengabaikan perilaku default ini.

Anda sendirian untuk menggarisbawahi, meskipun ...

GalacticCowboy
sumber
2

Bisakah Anda menggunakan atribut ActionName?

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

 }

Saya tidak berpikir hal penting. More_Details, more_DETAILS, mOrE_DeTaILs di URL semua membawa Anda ke Aksi Kontroler yang sama.

GuyIncognito
sumber
Saya belum mencobanya - akankah Anda menggunakan salah satunya? ("moredetails" atau "more_details")
GalacticCowboy
Untuk menindaklanjutinya, saya mencobanya dan mengharuskan Anda untuk menggunakan nama yang ditentukan, jadi tidak, itu tidak akan memungkinkan Anda untuk menanganinya. Juga, tergantung bagaimana Anda membuat aksi dan tampilan pengontrol, Anda mungkin perlu menentukan nama tampilan secara eksplisit.
GalacticCowboy