2010-01-15 7 views
30

Gibt es eine einfache Möglichkeit, den MvcRouteHandler alle Bindestriche in den Aktions- und Controllerabschnitten einer eingehenden URL in Unterstriche zu konvertieren, da Bindestriche in Methoden- oder Klassennamen nicht unterstützt werden.ASP.net MVC-Unterstützung für URLs mit Bindestrichen

Dies wäre so, dass ich solche Strukturen wie sample.com/test-page/edit-details Mapping zu Action edit_details und Controller test_pagecontroller bei der Verwendung der MapRoute-Methode unterstützen könnte.

Ich verstehe, dass ich ein Aktionsnamensattribut spezifizieren kann und Bindestriche in den Kontrollernamen unterstütze, die manuell Wege addieren, um dieses zu erzielen, aber ich suche nach einem automatisierten Weg, also Fehler beim Hinzufügen neuer Kontroller und Aktionen.

+6

Bindestriche werden in URLs als benutzerfreundlicher angesehen. Unterstriche kollidieren mit unterstrichenen Links. –

+2

mögliches Duplikat von [Asp.Net MVC: Wie aktiviere ich Bindestriche in meinen URLs?] (Http://stackoverflow.com/questions/30310/asp-net-mvc-how-do-i-enable-dashes-in- -my-urls) –

+0

Sie können sich diesen Artikel ansehen, der zeigt, wie man einen [benutzerdefinierten MvcRouteHandler] implementiert (http://codingcockerel.co.uk/2008/05/26/custom-routing-for-asp-net-net- mvc /). –

Antwort

18

Ich habe eine Lösung erarbeitet. Der requestContext innerhalb des MvcRouteHandler enthält die Werte für den Controller und die Aktion, für die Sie einen einfachen Ersetzungsvorgang durchführen können.

Public Class HyphenatedRouteHandler 
    Inherits MvcRouteHandler 

    Protected Overrides Function GetHttpHandler(ByVal requestContext As System.Web.Routing.RequestContext) As System.Web.IHttpHandler 
     requestContext.RouteData.Values("controller") = requestContext.RouteData.Values("controller").ToString.Replace("-", "_") 
     requestContext.RouteData.Values("action") = requestContext.RouteData.Values("action").ToString.Replace("-", "_") 
     Return MyBase.GetHttpHandler(requestContext) 
    End Function 

End Class 

Dann alles, was Sie brauchen den routes.MapRoute mit einem gleichwertigen routes.Add Angabe den die neuen Route-Handler zu ersetzen. Dies ist erforderlich, da Sie in MapRoute keinen benutzerdefinierten Routen-Handler angeben können.

routes.Add(New Route("{controller}/{action}/{id}", New RouteValueDictionary(New With {.controller = "Home", .action = "Index", .id = ""}), New HyphenatedRouteHandler())) 
+0

Wie würden Sie @ Html.Actionlink verwenden, um auf die Bindestrich-URL zu zeigen? @ Html.ActionLink ("Test", "Aktion", "ControllerName-Bindestrich") In dem obigen Fall weiß actionlink nicht, wie mit den Bindestrichen umzugehen, würde ich eine andere Erweiterung erstellen müssen, die die "- ersetzen würde "mit" "? Ich möchte, dass die generierte URL den Bindestrich enthält – DotnetShadow

+0

Schreiben Sie Ihren Aktionslink mit den Bindestrichen, wenn der MVC die Route nachschlägt, verwendet er den SilbentrennerRoutenHandler, um ihn aufzulösen und die vollständige URL zu generieren. – John

+0

Ok ok sieht so aus, als ob es gut funktioniert, ich habe gerade ein Problem mit der Syntaxprüfung von resharper bekommen, weil es nichts über das Mapping weiß. – DotnetShadow

0

Kennen einer Art und Weise nicht eine Karte für jede URL ohne das Schreiben:

routes.MapRoute("EditDetails", "test-page/edit-details/{id}", new { controller = "test_page", action = "edit_details" }); 
+0

Dies ist, was ich mit "manuell hinzufügen von Routen" gemeint habe und was ich vermeiden möchte. – John

31

C# Version von Johns Beitrag für jeden, der es vorziehen würde: C# and VB version on my blog

public class HyphenatedRouteHandler : MvcRouteHandler{ 
     protected override IHttpHandler GetHttpHandler(RequestContext requestContext) 
     { 
      requestContext.RouteData.Values["controller"] = requestContext.RouteData.Values["controller"].ToString().Replace("-", "_"); 
      requestContext.RouteData.Values["action"] = requestContext.RouteData.Values["action"].ToString().Replace("-", "_"); 
      return base.GetHttpHandler(requestContext); 
     } 
    } 

... und die neue Route:

routes.Add(
      new Route("{controller}/{action}/{id}", 
       new RouteValueDictionary(
        new { controller = "Default", action = "Index", id = "" }), 
        new HyphenatedRouteHandler()) 
     ); 

Sie können auch die folgende Methode verwenden, aber Denken Sie daran, dass Sie die Ansicht My-Action nennen müssen, was ärgerlich sein kann, wenn Sie Visual Studio automatisch Ihre View-Dateien generieren lassen möchten.

[ActionName("My-Action")] 
public ActionResult MyAction() { 
    return View(); 
} 
+0

Das funktionierte großartig ... aber pass auf für 'controller =" Default "'. Ich habe ein paar Mal ein 404 bekommen, bevor ich das bemerkt habe und es in "Home" geändert habe. –

+2

Wie würden Sie @ Html.Actionlink verwenden, um auf die Bindestrich-URL zu zeigen? @ Html.ActionLink ("Test", "Aktion", "ControllerName-Bindestrich") In dem obigen Fall weiß actionlink nicht, wie mit den Bindestrichen umzugehen, würde ich eine andere Erweiterung erstellen müssen, die die "- ersetzen würde "mit" "? Ich möchte, dass die generierte URL den Bindestrich enthält – DotnetShadow

14

Alles, was Sie in diesem Fall wirklich tun müssen, ist Ihre Ansichten mit den Bindestrichen nennen, wie Sie es in der URL angezeigt werden sollen, die Bindestriche in Ihrem Controller entfernen und dann eine Action Attribut hinzufügen, das die Bindestriche Rückseite hat drin. Es gibt keine Notwendigkeit, Unterstriche überhaupt zu haben.

Haben eine Ansicht edit-details.aspx

Und hat einen Controller wie folgt aufgerufen:

[ActionName("edit-details")] 
public ActionResult EditDetails(int id) 
{ 
    // your code 
} 
+0

Dies funktioniert für Aktionen, aber nicht für Controller, zumindest nicht in MVC 1 – John

9

ich dies durchaus eine alte Frage erkennen ist, aber für mich ist dies nur die Hälfte Geschichte der Akzeptanz von URLs mit Bindestrichen in ihnen, die andere Hälfte generiert diese URLs, während immer noch in der Lage, Html.ActionLink und andere Helfer im MVC-Framework zu verwenden, löste ich dies durch Erstellen einer benutzerdefinierten Route-Klasse ähnlich, hier ist der Code für den Fall Es hilft jedem, der von einer Google-Suche hierher kommt. Es enthält auch das untere Gehäuse der URL.

public class SeoFriendlyRoute : Route 
{ 
    // constructor overrides from Route go here, there is 4 of them 

    public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values) 
    { 
      var path = base.GetVirtualPath(requestContext, values); 

      if (path != null) 
      { 
       var indexes = new List<int>(); 
       var charArray = path.VirtualPath.Split('?')[0].ToCharArray(); 
       for (int index = 0; index < charArray.Length; index++) 
       { 
        var c = charArray[index]; 
        if (index > 0 && char.IsUpper(c) && charArray[index - 1] != '/') 
         indexes.Add(index); 
       } 

       indexes.Reverse(); 
       indexes.Remove(0); 
       foreach (var index in indexes) 
        path.VirtualPath = path.VirtualPath.Insert(index, "-"); 

       path.VirtualPath = path.VirtualPath.ToLowerInvariant(); 
      } 

      return path; 
    } 
} 

dann, wenn Routen hinzufügen, können Sie entweder eine Routecollection Erweiterungen erstellen oder benutzen Sie einfach den folgend in Ihren globalen Routing-Erklärungen

routes.Add(
     new SeoFriendlyRoute("{controller}/{action}/{id}", 
      new RouteValueDictionary(
       new { controller = "Default", action = "Index", id = "" }), 
       new HyphenatedRouteHandler()) 
    ); 
+0

Dies ist genau das, was ich gesucht habe. –

+1

Über der Antwort war nur das Ticket. Vielen Dank. Ich möchte auf die wichtige Ergänzung von Sylvia J aufmerksam machen (derzeit unten) –

2

Dank dsteuernol für diese Antwort - genau das, was ich suchte. Ich habe jedoch herausgefunden, dass ich den SilbentrennerRoutenHandler verbessern musste, um das Szenario abzudecken, in dem der Controller oder Bereich von der aktuellen Seite impliziert wurde. Zum Beispiel mit @ Html.ActionLink („My-Link“, „Index“)

änderte ich die GetHttpHandler Methode auf die folgenden:

public class HyphenatedRouteHandler : MvcRouteHandler 
    { 
     /// <summary> 
     /// Returns the HTTP handler by using the specified HTTP context. 
     /// </summary> 
     /// <param name="requestContext">The request context.</param> 
     /// <returns> 
     /// The HTTP handler. 
     /// </returns> 
     protected override IHttpHandler GetHttpHandler(RequestContext requestContext) 
     { 

      requestContext.RouteData.Values["controller"] = ReFormatString(requestContext.RouteData.Values["controller"].ToString()); 
      requestContext.RouteData.Values["action"] = ReFormatString(requestContext.RouteData.Values["action"].ToString()); 

      // is there an area 
      if (requestContext.RouteData.DataTokens.ContainsKey("area")) 
      { 
       requestContext.RouteData.DataTokens["area"] = ReFormatString(requestContext.RouteData.DataTokens["area"].ToString()); 
      } 

      return base.GetHttpHandler(requestContext); 
     } 


     private string ReFormatString(string hyphenedString) 
     { 
      // lets put capitals back in 

      // change dashes to spaces 
      hyphenedString = hyphenedString.Replace("-", " "); 

      // change to title case 
      hyphenedString = CultureInfo.InvariantCulture.TextInfo.ToTitleCase(hyphenedString); 

      // remove spaces 
      hyphenedString = hyphenedString.Replace(" ", ""); 

      return hyphenedString; 
     } 
    } 

Setzt man die Kapitelle zurück in gemeint, dass die implizite Steuerung oder Bereich war dann richtig verbunden.

1

Ich habe eine Open Source NuGet-Bibliothek für dieses Problem entwickelt, das EveryMvc/Url implizit in Every-MVC/URL konvertiert.

Gestrichelte URLs sind viel mehr SEO-freundlich und einfacher zu lesen. (More on my blog post)

NuGet Paket: https://www.nuget.org/packages/LowercaseDashedRoute/

es zu installieren, öffnen Sie einfach die NuGet Fenster in Visual Studio mit der rechten das Projekt klicken und NuGet Package Manager und auf der "Online" Tabulatortyp „Klein Dashed Auswahl Route ", und es sollte auftauchen.

Install-Package LowercaseDashedRoute

Danach sollten Sie App_Start/RouteConfig.cs öffnen und kommentieren Sie vorhandene route.MapRoute (...):

Alternativ können Sie diesen Code im Paket-Manager-Konsole ausführen Rufen Sie an und fügen Sie stattdessen Folgendes hinzu:

routes.Add(new LowercaseDashedRoute("{controller}/{action}/{id}", 
    new RouteValueDictionary(
    new { controller = "Home", action = "Index", id = UrlParameter.Optional }), 
    new DashedRouteHandler() 
) 
); 

Das ist es. Alle URLs sind kleingeschrieben, gestrichelt und implizit konvertiert, ohne dass Sie etwas mehr tun.

Open Source Projekt-URL: https://github.com/AtaS/lowercase-dashed-route

0

Wenn Sie Ihr Projekt MVC5 aktualisieren, können Sie die Verwendung von Attribut Routing machen.

[Route("controller/my-action")] 
public ActionResult MyAction() { 
    return View(); 
} 

ich viel lieber diese Annäherung an die akzeptierte Lösung, die Sie mit Unterstrichen in Ihrem Controller Aktionsnamen und Dateinamen Ansicht und Bindestriche in Ihrer Ansicht des Url.Action Helfer verlässt. Ich bevorzuge Konsistenz und muss mich nicht daran erinnern, wie die Namen konvertiert werden.