Wie kann ich in ASP.NET MVC Routen in Kleinbuchstaben verwenden?

145

Wie kann ich Routen in ASP.NET MVC in Kleinbuchstaben und wenn möglich mit Unterstrich versehen? Damit ich /dinners/details/2anrufen DinnersController.Details(2)und wenn möglich /dinners/more_details/2anrufen würde DinnersController.MoreDetails(2)?

All dies, während immer noch Muster wie verwendet werden {controller}/{action}/{id}.

J. Pablo Fernández
quelle
Ich habe ohnehin aus verschiedenen Gründen alle meine Routen manuell geschrieben und ich denke, es ist schwer zu vermeiden, dies mit etwas zu tun, das nicht nur CRUD ist. Also habe ich sie nur in Kleinbuchstaben geschrieben.
Pupeno
Mit Web Forms ? Gehen Sie hier: msdn.microsoft.com/en-us/library/… . (Ich konvertiere mein Projekt schrittweise von Webformularen zu MVC und habe beide im Projekt)
Jess
Ich denke nicht, dass es wichtig ist, wenn Sie die Routen in Klein- oder Großbuchstaben eingeben.

Antworten:

238

Mit System.Web.Routing 4.5 können Sie dies einfach implementieren, indem Sie die LowercaseUrls-Eigenschaft von RouteCollection festlegen:

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

Angenommen, Sie tun dies aus SEO-Gründen, um eingehende URLs in Kleinbuchstaben umzuleiten (wie in vielen Links in diesem Artikel erwähnt).

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
quelle
4
Dies ist bei weitem das Einfachste in 4.0.
Paul Turner
1
Ich wünschte, dies wäre an der Spitze ... Fast viel Code kultiviert!
Akatakritos
2
Tolle Antwort :-) Der letztere SEO-Teil passt gut in ein HTTP-Modul.
David Kirkland
1
@ Aaron Sherman Wohin soll der Application_BeginRequest-Teil gehen? Es gibt mir Fehler, wenn es innerhalb der öffentlichen Klasse RouteConfig ist und auch wenn es außerhalb von if ist.
Richard Mišenčík
1
@ richard-mišenčík fügen Sie es zur Global.asax-Datei hinzu
ITmeze
44

Diese beiden Tutorials haben mir geholfen, als ich das Gleiche tun und gut arbeiten wollte:

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

BEARBEITEN: Für Projekte mit Bereichen müssen Sie die GetVirtualPath () -Methode ändern:

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
quelle
9
GONeale Link hat sich geändert; URL ist jetzt goneale.com/2008/12/19/lowercase-route-urls-in-aspnet-mvc
Daniel Liuzzi
4
@Derek - Nein, die Tutorials werden bei Verwendung von Area's unterbrochen. Nachdem ich 3 Tage lang ALLES ausprobiert hatte ... fand ich eine bessere Lösung, es gibt eine Bibliothek namens Attribute Routing. Löst das Problem und erleichtert das Leben erheblich. philliphaydon.com/2011/08/…
Phill
6
Für mvc 4 gibt es eine bessere Lösung mit Eigenschaftsrouten.LowercaseUrls = true; Weitere Informationen auf dhuvelle.com/2012/11/tips-for-aspnet-mvc-4-lowercase-urls.html
Marc Cals
4
@GONeale Was ist mit deiner URL passiert? Der zweite Link ist jetzt tot! Hat mich zum Lachen gebracht, der Titel lautet "The Best Gone Ale Site im Internet"
Luke
2
@chteuchteu dieser Link hat bei mir nicht funktioniert, aber dieser hat funktioniert.
Chue x
22

Wenn Sie geschehen ASP.NET - Core zu verwenden, sollten Sie vielleicht einen Blick auf haben dies :

Fügen Sie der ConfigureServicesMethode der StartupKlasse die folgende Zeile hinzu .

services.AddRouting(options => options.LowercaseUrls = true);
Ebrahim Byagowi
quelle
1
Gleiches gilt für Core 2.0. Auch bei stackoverflow.com/a/45777372/195755
yzorg
21

Wenn Sie den UrlHelper zum Generieren des Links verwenden, können Sie einfach den Namen der Aktion und des Controllers in Kleinbuchstaben angeben:

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

Ergebnisse in: / media / photos / delete / 64 (obwohl mein Controller und meine Aktion ein Pascal-Fall sind).

Matt
quelle
16
Ich denke, diese Arbeit an einem zentralen Ort zu erledigen, ist die einfachste und Standardlösung. Dies ist genauso schlecht wie Inline-CSS. (Anscheinend verwenden 15 Personen Inline-CSS).
Der Muffin-Mann
Gilt das auch für Linux-Server?
QMaster
15

Ich fand dies im Coder Journal von Nick Berardi , aber es gab keine Informationen darüber, wie die LowercaseRouteKlasse implementiert werden sollte . Daher hier mit zusätzlichen Informationen neu posten.

Erweitern Sie zuerst die RouteKlasse aufLowercaseRoute

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

Ändern Sie dann die RegisterRoutesMethode von 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
    //);
}

Ich würde jedoch gerne wissen, wie man Routen verwendet. MapRoute ...

John Oxley
quelle
GONeales Artikel bietet eine Erweiterungsmethode, mit der Sie schreiben können, routes.MapRouteLowercase(...die besser
Drew Noakes
1
GONeales gesamter Blog verschwand. Hier ist ein weiterer Blogeintrag mit ähnlichem Inhalt (und derselben Erweiterungsmethode). Es befasst sich mit dieser Situation im Zusammenhang mit der Reduzierung doppelter Inhalte.
Patridge
11

Sie können die MapRoute-Syntax weiterhin verwenden, indem Sie diese Klasse als Erweiterung zu RouteCollection hinzufügen:

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

Jetzt können Sie im Start Ihrer Anwendung "MapRouteLowerCase" anstelle von "MapRoute" verwenden:

    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
quelle
Für jeden, der dies liest, LowercaseRoutescheint die Klasse im ersten Code-Snippet oben von dieser anderen Antwort
chue x
6

Dies hat tatsächlich zwei Antworten:

  1. Dies können Sie bereits tun: Die Routen-Engine führt einen Vergleich ohne Berücksichtigung der Groß- und Kleinschreibung durch. Wenn Sie eine Route in Kleinbuchstaben eingeben, wird diese an den entsprechenden Controller und die entsprechende Aktion weitergeleitet.
  2. Wenn Sie Steuerelemente verwenden, die Routenverknüpfungen generieren (ActionLink, RouteLink usw.), werden Links in Groß- und Kleinschreibung erstellt, sofern Sie dieses Standardverhalten nicht überschreiben.

Für die Unterstriche bist du allein ...

GalacticCowboy
quelle
2

Könnten Sie das ActionName-Attribut verwenden?

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

 }

Ich denke nicht, dass der Fall wichtig ist. More_Details, more_DETAILS, mOrE_DeTaILs in der URL führen Sie alle zur gleichen Controller-Aktion.

GuyIncognito
quelle
Ich habe das nicht ausprobiert - können Sie eines davon verwenden? ("moredetails" oder "more_details")
GalacticCowboy
Um dies zu verfolgen, habe ich es versucht und es erfordert, dass Sie den angegebenen Namen verwenden. Nein, es erlaubt Ihnen nicht, damit umzugehen. Abhängig davon, wie Sie Ihre Controller-Aktion und -Ansicht erstellt haben, müssen Sie möglicherweise den Namen der Ansicht explizit angeben.
GalacticCowboy