ASP.NET MVC Routing: Play Traffic Cop with Your Routes

December 17th, 2014

As an ASP.NET MVC request is received, the routing sends the request to the proper controller. Today, we talk about how to use routing, some tips on using them effectively, and how to debug them easily.

Routing in ASP.NET MVC is one of the basic steps in the MVC Application Processing Pipeline. Since most developers don't see a need to adjust their routing, they leave it alone and carry on with their application.

But what happens when you need to make some adjustments to your MVC page structure? As Google has mentioned, you want to make sure you have SEO-friendly URLs. This means you may need to fix up your site so that Google, Bing, and/or Yahoo! can find your breadcrumb trail through your URL site structure.

NOTE: Download and Review the Lifecycle of an ASP.NET MVC 5 Application to understand what happens when routing occurs (PDF).

Routing Basics

I know I mentioned that I consider UrlHelpers as a table of contents for your application, but routing is also a way to find out how the application is structured. If you are just getting into an ASP.NET MVC application for the first time with a client, I would definitely recommend that you ask them where the UrlHelpers and Routing are located in the application.

If you get a blank stare or they say they just use ActionLinks throughout their application, I would start to worry.

Ok, now I'm referring to that lifecycle document you should've downloaded from above.

When a web request first comes in to your application, it reads the Global.asax.cs class to setup the routes for your application, then heads to the App_Start\RouteConfig.cs file, and registers the routes defined in the static class. It only happens once.

If you don't have a need to modify your routes, you can leave them alone.

Here is the default route with an explanation below:

Default Route

routes.MapRoute(
    name: "Default",
    url: "{controller}/{action}/{id}",
    defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);

The MapRoute method defines the following:

Once the {controller}, {action}, and {id} are identified, those values are matched to the signature of the controller, action, and other parameters.

Notice I didn't say 'id'? Id can be optional. Heck, it can even be a different parameter signature in the controller.

So if we had the following URL:

http://www.danylkoweb.com/Blog/Detail/15

The route would breakdown the URL into the following route values:

The general rule is that the route defaults MUST match the action's parameters exactly. It is case sensitive.

"But I want easy-to-read URLs!"

Let's look at a harder example. How about DanylkoWeb, to be more specific?

Notice the URL at the top:

http://www.danylkoweb.com/Blog/aspnet-mvc-routing-play-traffic-cop-with-your-routes-90

But how do you know which action it goes to? It sure doesn't go to the "aspnet-mvc-routing-play-traffic-cop-with-your-routes-90" method, does it?

No, it doesn't. Here the trick and the route to pull it off:

routes.MapRoute(
    name: "BlogDetail",
    url: "Blog/{title}-{id}",
    defaults: new { controller = "Blog", action = "Detail", title = String.Empty, id = UrlParameter.Optional },
    namespaces: new string[] { "DanylkoWeb.Controllers" }
);

Let's take it step by step.

Everything looks the same regarding the controller name (Blog), but we have a different parameter type in the URL. Remember when I said you can have different parameters in your URL? This is what I'm talking about when I mentioned it above.

The key here is the last dashed word in the URL. The ID is the last number after the last dash, which is 90. That "id" is passed into the detail method in your Blog controller:

public ActionResult Detail(string id)
{
   // LoadById(id) - load post id 90
   .
. }

If you want to include the title in the method signature along with the id, just add "string title," in the method and act on it.

Using Large URLs

One project I worked on in the past was a link directory structure. It was a recursive database table with a lot of locations. A sample URL looked like this:

http://www.domain.com/LinkDirectory/NorthAmerica/UnitedStates/Ohio/Columbus

So how would you break this down to a route?

You would create a route like this:

routes.MapRoute(
    "LinkData",        // Route name
    "LinkDirectory/{*data}"// URL with parameters
    new { controller = "LinkDirectory", action = "Category" }
);

Ok, see the *data?

The asterisk is a catch-all parameter. It will match and pass /NorthAmerica/UnitedStates/Ohio/Columbus to the LinkDirectory.Category method. As before, make sure the category action method has a parameter (data) that matches the MapRoute parameter name (data).

The method would look like this:

public ActionResult Category(string data, int? page)
{
    // data = "/NorthAmerica/UnitedStates/Ohio/Columbus"
}

At this point, you can now parse the URL and load the data.

Debugging Routes

If you have a large application that contains many routes, it may be difficult to track down each and every route coming in to your application. It can be quite maddening!

Here are a few tips to make debugging your routes easier so you don't lose your sanity. ;-)

Conclusion

ASP.NET MVC Routing becomes extremely important when you expect a URL to go to a certain controller and it diverts the request to another page altogether.

If you understand the basics and keep your routes simple, you may still be able to keep your sanity (for now) ;-)

References:

Do you have any other Route Debugging tips? Post them below!