Better looking URLs in ASP.NET MVC 3

If you are like me and thought the conventions for action/controller names in ASP.NET MVC 3 were not great (capitalizations are evil), here’s a small trick to make them look nicer.

Let’s say we have a controller name that consists of more than two words, i.e. FooBarController and it has an action called “FooBaz“. Normally ASP.NET MVC will map the url as "~/FooBar/FooBaz". I don’t like this naming convention very much and would rather prefer "~/foo-bar/foo-baz". So how do we go on achieving this?

It seems that the normal routing options do not support this kind of behavior. You can add a custom route for every controller with a long name and use the [ActionName] attribute on actions. However I wanted to see if a more uniform solution was possible to achieve.

The first way that I investigated was writing my own IRouteHandler which allows you to change the default routing as you see fit. This requires you to write your own IHttpHandler, which is the main request processing pipe in ASP.NET MVC 3. Looking at the source of ASP.NET MVC 3 System.Web.Mvc.MvcHandler, this seemed doable by copy pasting and changing the way it resolves the controller name. This felt wrong however, as making a copy of the whole request processing pipe for a cosmetic task seemed like an overkill.

There seems to be a much easier way to achieve this, by using the ControllerFactory injection that is possible in ASP.NET MVC 3. As you might know, it is possible to override the behavior of ASP.NET MVC 3 for initializing controllers. As such, you can create your own DelimiterControllerFactory implementation.

public class DelimiterControllerFactory : DefaultControllerFactory
    {
        public override IController CreateController(RequestContext requestContext,
            string controllerName)
        {
            requestContext.RouteData.Values["action"] =
                requestContext.RouteData.Values["action"].ToString().Replace("-", "");
            return base.CreateController(requestContext, controllerName.Replace("-", ""));
        }
    }

You can then plug this controller in during your Application_Start() in Global.asax.

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
    ControllerBuilder.Current.SetControllerFactory(new DelimiterControllerFactory());
    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);
}

Now when you go to /foo-bar/foo-baz it will resolve to FooBarController.FooBaz(). Keep in mind you need to rename your View directories to foo-bar instead of FooBar. It might be possible to have the old behavior by overriding the View() method on the controller, however this is just about how you name your folders internally in your project.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s