Geeks With Blogs

News
Joe Mayo

One of the first things I build for a new feature in MVC is a controller, with actions. For the C# Tutorial at C# Station, I built a CSharpTutorial controller and began looking at what actions were necessary. Considering the tutorial is at 23 lessons and growing, it doesn’t make much sense to create that many actions; especially with the glaring redundancy. The solution in this situation is a custom route. The following route definition solves this problem by isolating a parameter, lessonNumber:

        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                "CSharpTutorial",
                "CSharpTutorial/Lesson{lessonNumber}",
                new { controller = "CSharpTutorial", action = "Lesson" }
            );

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

This is the RegisterRoutes method that resides in Global.asax.cs.  The custom route is CSharpTutorial, which appears before the Default route. More specific routes should appear before more general routes because MVC routing search uses a first match wins resolution strategy.

The route URL parameter appends lessonNumber to the Lesson action.  The lessonNumber parameter doesn’t have a default value because I want the user to supply it.  Also, I want lessonNumber to appear after the URL generation process, which wouldn’t happen if the value matches the default. The following ActionLink depends on the CSharpTutorial route:

@Html.ActionLink(
    "Lesson 01",
    "Lesson",
    "CSharpTutorial",
    new { lessonNumber = "1" },
    null)

Yes, that’s MVC 3 Razor view engine syntax. The controller, action, and  route parameters match the custom CSharpTutorial route above. Here’s the generated URL:

/CSharpTutorial/Lesson1

This is a hackable URL, allowing users to change the lesson number to /CSharpTutorial/Lesson2 or /CSharpTutorial/Lesson23 and it will still work. Going back to the controller, here’s how to code requests for all lessons in a single action:

        public ActionResult Lesson(int lessonNumber)
        {
            if (lessonNumber > 23)
                return HttpNotFound();

            return View("Lesson" + lessonNumber.ToString().PadLeft(2, '0'));
        }

The custom route allows parsing out the lessonNumber so that model binding will pass the right value to the action. i.e. if the URL is /CSharpTutorial/Lesson17, the lessonNumber value will be 17.

Notice the HttpNotFound action result; this is another new MVC 3 feature. There are only 23 lessons, so I’m using this to tell the user they’ve requested a non-existent page if they typed in an invalid page number, such as /CSharpTutorial/Lesson42. The user has the  choice of typing one or two digits, but it doesn’t matter because the actual views are named with two digits; facilitated by the call to PadLeft.

Although you can write an entire application with the default route, the ability to add custom routes can enhance your development and user experience. This example leveraged a custom route to reduce code and allow the sophisticated user to navigate to whatever lesson they want through the browser address bar.

Joe

Posted on Sunday, October 31, 2010 11:07 PM | Back to top

Copyright © Joe Mayo | Powered by: GeeksWithBlogs.net