78

I'd like to have dashes separate words in my URLs. So instead of:

/MyController/MyAction

I'd like:

/My-Controller/My-Action

Is this possible?

Jim Geurts
  • 20,189
  • 23
  • 95
  • 116
  • possible duplicate of [ASP.net MVC support for URL's with hyphens](http://stackoverflow.com/questions/2070890/asp-net-mvc-support-for-urls-with-hyphens) – John Feb 04 '11 at 09:13
  • 2
    @John the question you linked is a possible duplicate not this, see the dates, that question is asked around 2 yrs later than this – Abhishek Siddhu May 25 '16 at 07:29

9 Answers9

157

You can use the ActionName attribute like so:

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

Note that you will then need to call your View file "My-Action.cshtml" (or appropriate extension). You will also need to reference "my-action" in any Html.ActionLink methods.

There isn't such a simple solution for controllers.

Edit: Update for MVC5

Enable the routes globally:

public static void RegisterRoutes(RouteCollection routes)
{
    routes.MapMvcAttributeRoutes();
    // routes.MapRoute...
}

Now with MVC5, Attribute Routing has been absorbed into the project. You can now use:

[Route("My-Action")]

On Action Methods.

For controllers, you can apply a RoutePrefix attribute which will be applied to all action methods in that controller:

[RoutePrefix("my-controller")]

One of the benefits of using RoutePrefix is URL parameters will also be passed down to any action methods.

[RoutePrefix("clients/{clientId:int}")]
public class ClientsController : Controller .....

Snip..

[Route("edit-client")]
public ActionResult Edit(int clientId) // will match /clients/123/edit-client
Ognyan Dimitrov
  • 6,026
  • 1
  • 48
  • 70
ChadT
  • 7,598
  • 2
  • 40
  • 57
  • 1
    This is the real answer. Not sure why Phil didn't add this info – Eduardo Molteni Mar 10 '09 at 14:09
  • 2
    Nice tip. Just to add: When you do this with the default View() invocation, MVC will search for "My-Action.aspx" somewhere in the Views folder, not "MyAction.aspx," unless you explicitly specify the original name. – Nicholas Piasecki Apr 22 '09 at 01:27
  • @Eduardo I think the ActionName attribute was added for Preview 5, which came out just after Phil's post. – David Kolar Aug 20 '09 at 14:49
  • How do you explicitly specify the view file name? Do I have to change the views file name to My-Action.aspx? – Alex May 31 '10 at 16:10
  • @Alex, yes, you set the view file name to be whatever the parameter is in the ActionName attribute. "My-Action.aspx" for instance. – ChadT Jun 01 '10 at 01:23
  • I posted an identical question before I found this one. For those who don't want to rename their view to `My-Action.*`, check out the answer I received http://stackoverflow.com/questions/18584503/asp-net-mvc-routing-clean-urls-from-camel-case-to-hyphenated-words – Brett Sep 03 '13 at 06:06
  • I tried using the Route attribute on an action method. The attribute has the name with dashes, the method without dashes or underscores and the view with dashes. However, it does not seem to work in my MVC5 project. – Lord of Scripts Dec 10 '14 at 18:30
  • 4
    @LordofScripts - make sure that you've configured routing appropriately with: routes.MapMvcAttributeRoutes(); – ChadT Dec 11 '14 at 01:41
  • @DaRKoN_ I follow the same pattern so that only 1 route is used (default). All other actions work except that one. Everything else is stock MVC5 – Lord of Scripts Dec 12 '14 at 21:52
  • Routes for actions work for me, but RoutePrefix for controllers dont I just get not found error – Richard Mišenčík Jun 08 '15 at 13:39
  • i am no longer able to add view with `dash` as said [here](http://forums.asp.net/t/1998192.aspx?Can+no+longer+add+views+with+periods+in+the+name+Visual+Studio+Pro+2013+) , when tried this appears: `The name is not allowed to contain any of these characters: . - @ <`, . so i guess only solution is to rename the view after adding – Shaiju T Jan 27 '16 at 10:30
  • Can we use `RoutePrefix` source code from github to add it in mvc 4 ? – Shaiju T Oct 25 '16 at 08:38
16

You could create a custom route handler as shown in this blog:

http://blog.didsburydesign.com/2010/02/how-to-allow-hyphens-in-urls-using-asp-net-mvc-2/

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

...and the new route:

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

A very similar question was asked here: ASP.net MVC support for URL's with hyphens

Community
  • 1
  • 1
Andrew
  • 9,967
  • 10
  • 64
  • 103
11

I've developed an open source NuGet library for this problem which implicitly converts EveryMvc/Url to every-mvc/url.

Uppercase urls are problematic because cookie paths are case-sensitive, most of the internet is actually case-sensitive while Microsoft technologies treats urls as case-insensitive. (More on my blog post)

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

To install it, simply open the NuGet window in the Visual Studio by right clicking the Project and selecting NuGet Package Manager, and on the "Online" tab type "Lowercase Dashed Route", and it should pop up.

Alternatively, you can run this code in the Package Manager Console:

Install-Package LowercaseDashedRoute

After that you should open App_Start/RouteConfig.cs and comment out existing route.MapRoute(...) call and add this instead:

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

That's it. All the urls are lowercase, dashed, and converted implicitly without you doing anything more.

Open Source Project Url: https://github.com/AtaS/lowercase-dashed-route

Ata S.
  • 890
  • 7
  • 12
8

Here's what I did using areas in ASP.NET MVC 5 and it worked liked a charm. I didn't have to rename my views, either.

In RouteConfig.cs, do this:

 public static void RegisterRoutes(RouteCollection routes)
    {
        // add these to enable attribute routing and lowercase urls, if desired
        routes.MapMvcAttributeRoutes();
        routes.LowercaseUrls = true;

        // routes.MapRoute...
    }

In your controller, add this before your class definition:

[RouteArea("SampleArea", AreaPrefix = "sample-area")]
[Route("{action}")]
public class SampleAreaController: Controller
{
    // ...

    [Route("my-action")]
    public ViewResult MyAction()
    {
        // do something useful
    }
}

The URL that shows up in the browser if testing on local machine is: localhost/sample-area/my-action. You don't need to rename your view files or anything. I was quite happy with the end result.

After routing attributes are enabled you can delete any area registration files you have such as SampleAreaRegistration.cs.

This article helped me come to this conclusion. I hope it is useful to you.

Daniel Eagle
  • 2,205
  • 2
  • 18
  • 17
3

Asp.Net MVC 5 will support attribute routing, allowing more explicit control over route names. Sample usage will look like:

[RoutePrefix("dogs-and-cats")]
public class DogsAndCatsController : Controller
{
    [HttpGet("living-together")]
    public ViewResult LivingTogether() { ... }

    [HttpPost("mass-hysteria")]
    public ViewResult MassHysteria() { }
}

To get this behavior for projects using Asp.Net MVC prior to v5, similar functionality can be found with the AttributeRouting project (also available as a nuget). In fact, Microsoft reached out to the author of AttributeRouting to help them with their implementation for MVC 5.

Jim Geurts
  • 20,189
  • 23
  • 95
  • 116
1

You can define a specific route such as:

routes.MapRoute(
    "TandC", // Route controllerName
    "CommonPath/{controller}/Terms-and-Conditions", // URL with parameters
    new {
        controller = "Home",
        action = "Terms_and_Conditions"
    } // Parameter defaults
);

But this route has to be registered BEFORE your default route.

Yuck
  • 49,664
  • 13
  • 105
  • 135
Nexxas
  • 883
  • 1
  • 8
  • 14
  • Similarly, using [AttributeRouting](http://attributerouting.net/) allows you to specify any route name you want, with the added benefit of knowing exactly which route your action is associated with. – Jim Geurts Dec 09 '12 at 16:03
1

You could write a custom route that derives from the Route class GetRouteData to strip dashes, but when you call the APIs to generate a URL, you'll have to remember to include the dashes for action name and controller name.

That shouldn't be too hard.

Haacked
  • 58,045
  • 14
  • 90
  • 114
  • Phil is right (as usual). There's a great example that I can't take credit for, but I'm grateful I found. It's by an MVP, and you can find it [here](http://www.campusmvp.net/asp-net-mvc-friendlier-action-names-and-controllers/). – Daniel Cox Jan 21 '13 at 21:59
  • Here is my NuGet package for this implementation: https://www.nuget.org/packages/LowercaseDashedRoute/ Don't forget to read the README on GitHub (via Project Info link on NuGet page) – Ata S. Aug 03 '13 at 11:39
0

If you have access to the IIS URL Rewrite module ( http://blogs.iis.net/ruslany/archive/2009/04/08/10-url-rewriting-tips-and-tricks.aspx ), you can simply rewrite the URLs.

Requests to /my-controller/my-action can be rewritten to /mycontroller/myaction and then there is no need to write custom handlers or anything else. Visitors get pretty urls and you get ones MVC can understand.

Here's an example for one controller and action, but you could modify this to be a more generic solution:

<rewrite>
  <rules>
    <rule name="Dashes, damnit">
      <match url="^my-controller(.*)" />
      <action type="Rewrite" url="MyController/Index{R:1}" />
    </rule>
  </rules>
</rewrite>

The possible downside to this is you'll have to switch your project to use IIS Express or IIS for rewrites to work during development.

Cory Mawhorter
  • 1,583
  • 18
  • 22
0

I'm still pretty new to MVC, so take it with a grain of salt. It's not an elegant, catch-all solution but did the trick for me in MVC4:

routes.MapRoute(
    name: "ControllerName",
    url: "Controller-Name/{action}/{id}",
    defaults: new { controller = "ControllerName", action = "Index", id = UrlParameter.Optional }
);
gregtheross
  • 385
  • 4
  • 9