Creating GeoGeekTV: Setting up Routes

Welcome back to my on-going series about the creation of GeoGeekTV.com. Having solidified the design, we can move on to the implementation.

Since ASP.NET MVC abstracts the requested URL from actual files on disk (as in /foo/bar.htm does not actually load a the bar.htm file in the foo folder), we have a lot more control of the Urls. Thus, it’s worth taking a little time at the beginning of a project to decide how we want the Urls to work

For GeoGeekTV, we have a few main areas: Home Page, the Live Stream, Upcoming Shows, the Archive, a Contact page, Backstage and Admin.

Since most of these are pretty simple pages, we can use the default routing for the most part.

The default route  uses the /{controller}/{action}/{id} pattern to make an incoming request to a controller and action (aka a method).

When we setup routes, we assign defaults to the components of the route. So for our site, we users to land at the home page, so we setup the default for the route to be “home”. As for a default action, we usually use “index”. Since an id does not have much context on some controllers, we default that to an empty string.

This is what the route looks like in the Global.asax.cs file:

routes.MapRoute(
    "Default",                                              // Route name
    "{controller}/{action}/{id}",                           // URL with parameters
    new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
);

I like to map out the urls for an application in a table. This helps get an idea of how the routes should be setup, and it also provides a development road map for the controllers and actions we’ll need.

Url Controller Action Description
/Home Home Index The home page
/Live Live Index The live streaming page. If we are not live, show a list of recent shows
/Archive or

/Archive/List
Archive List Paged list of Archive shows
/Archive/View/{name} Archive View View a show from the archive
/Archive/tag/{tag} Archive tag View list of shows that have a particular tag
/Contact Contact Index The Contact form
/Backstage Backstage Index The backstage page
/Upcoming Upcoming List List of upcoming shows
/Upcoming/Edit/{id} Upcoming Edit Edit an upcoming show
/Upcoming/Create Upcoming Create Create an upcoming show entry
/Archive/Create Archive Create Create an entry in the archive
/Archive/Edit/{id} Archive Edit Edit an entry in the archive
/Login Login Index Login screen
/Admin Admin Index Main Admin Screen

Conveniently, for GeoGeekTV.com we can pretty much live with this default route, with one exception.  We are going to support a simple tagging system on the shows, and it would be handy to have a url that would list all the shows related to a tag. Now, if we wanted to use the ID of the Tag in the url (i.e. the “Unit Testing” tag has an ID of 27, so the url would be /Archive/Tag/27) our default route would still work. But I think it would be more useful to have human readable tags, so we’ll use the actual tag in the url.

So I’ll create an additional route.

routes.MapRoute(
    "Archive",                                                // Route name
    "Archive/Tag/{tag}",                                      // URL with parameters
    new { controller = "Archive", action = "Tag", tag = "" }  // Parameter defaults
);

This new route is very specific – it only applies to the /Archive/Tag url, and will now pass in a parameter named “tag” to the controller method.

 

Testing the Routes

We can write unit tests to ensure that the routing is working as designed. Since this is just testing the routing, we don’t actually need to create any controllers or views – we are just testing the routes in Global.asax.cs

[Test]
public void archive_tag_tag_route()
{
    MvcApplication.RegisterRoutes(RouteTable.Routes);
    var httpContext = MockRepository.GenerateStub<HttpContextBase>();

    httpContext.Stub(x => x.Request).Return(MockRepository.GenerateStub<HttpRequestBase>());
    httpContext.Request.Stub(x => x.PathInfo).Return("");
    httpContext.Request.Stub(x => x.AppRelativeCurrentExecutionFilePath).Return("~/Archive/Tag/foo");

    var routeData = RouteTable.Routes.GetRouteData(httpContext);
    Assert.AreEqual(routeData.Values["controller"], ("Archive"));
    Assert.AreEqual(routeData.Values["action"], ("Tag"));
    Assert.AreEqual(routeData.Values["tag"], ("foo"));
}

Although this is somewhat long-winded, and there are other more elegant options, I just keep this snipped of code lying around and drop it in as needed.

Although pretty simple at this point, I’ve pushed this into the repository over on assembla.com if you want to check out the code.

Up Next:

We’ve already created a simple out of the box ASP.NET MVC 2 web application. Next time we’ll layout the other projects in the solution, clear out the un-needed cruft from the MVC project and setup our dependency injection. From there we’ll actually start writing some code!

Advertisement
This entry was posted in Uncategorized. Bookmark the permalink.

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 )

Connecting to %s