Practical ASP.NET

Supporting Routing

Want to make life easier for your users? NET 3.5 SP1's routing technology has some extra features to let you do just that.

In two previous columns ("Routing Your ASP.NET Application" and "Decoding Routes"), I looked at how you can configure your site to disconnect the URLs that your users will provide from the virtual paths to your pages. This column goes beyond those basics to look at some additional features of routing. The goals here are to simplify your code and make life easier for your users.

When you set up a route, you specify a template for the URL that users will provide. The template that I've been using looks like this:

Inventory/{action}/{itemid}

A sample URL with "Details" plugged into the action parameter and "A1234" plugged into the itemid would look like this:

http://www.mysite.com/MyApp/Inventory/Details/A1234

Simplifying Your Code
The first issue to address is that not all URLs that users can provide will be valid. For instance, for the action parameter, I'm only willing to accept "Details" and "List." I could check for those entries by adding more code to the class that decodes URLs, but a better solution is to let the Routing object do it by setting a constraint. If you specify a constraint and the user enters an invalid URL, the user gets back the standard HTTP 404 error.

The Constraints property on a Route object accepts a RouteValueDictionary object. When you create a RouteValueDictionary object, you pass a new anonymous type with properties that correspond to your template's parameters. You use regular expression syntax to specify valid entries for each of your parameters.

This example creates a constraint that specifies that my action parameter must be either "List" or "Details"; my itemid must either begin with the letter A and be followed by four digits or be the word "All":

Dim rvd As Routing.RouteValueDictionary 
rvd = New Routing.RouteValueDictionary(New With _
   {.action = "Details|List", .itemid = "[A]\d{4}|All"})
rt.Constraints = rvd

Going back to the code in a previous column ("Decoding Routes") I can now eliminate the code that checked for invalid entries in the action parameter -- those URLs will no longer be passed to my decoder. Of course, just because you can use a constraint to prevent invalid entries, doesn't mean you should stop there. The 404 error message doesn't give the user much help in figuring out what a valid URL should look like. Now that you're providing users with meaningful URLs, you can use IIS' ability to specify custom error pages to send users a page that describes what a valid URL looks like.

Most of the time, all the data that your decoding process will need will be provided by the user's entries to your URL template. However, you may occasionally need data that's available at the time that the Route is created. The DataTokens property is designed to provide you with a place to attach additional information to a route when you define it.

The DataTokens property on the Route object also accepts RouteValueDictionary object. When decoding the route, you can access that value by name and use it for, well, whatever you need. Effectively, the DataTokens property functions like the Tag property that many user interface controls include that provide the developer with a place to store data that doesn't affect the way that the control behaves.

This code, for instance, attaches the date and time that the Route was created to the Route as a DataToken named "dateCreated":

rvd = New Routing.RouteValueDictionary(New With _
   {.dateCreated = Now()})
rt.DataTokens = rvd

You can retrieve any DataTokens by name in the class that decodes your Routes through the requestContext parameter's DataTokens collection, as this example does:

Dim dt As DateTime
dt = Convert.ToDateTime( _
   requestContext.RouteData.DataTokens("dateCreated"))

Making Life Easier for Users
One other feature of the Route object lets you provide default values for your users. What happens, for instance, if a user enters a URL that omits any of the parameters for the template?

http://www.MyServer.com/MySite/Inventory

For the application that I've been describing, the appropriate page to send back might be a list of all products. The meaningful URL that would give that page would have "List" in the action parameter and "All." This code creates yet another RouteValueDictionary and supplies values for my action and itemid parameters. I then set my Route object's Defaults to this dictionary:

rvd = New Routing.RouteValueDictionary(New With _
   {.action = "List", .itemid = "All"})
rt.Defaults = rvd

With these few changes, I've simplified my routing code and made it easier for users to access the site.

About the Author

Peter Vogel is a system architect and principal in PH&V Information Services. PH&V provides full-stack consulting from UX design through object modeling to database design. Peter tweets about his VSM columns with the hashtag #vogelarticles. His blog posts on user experience design can be found at http://blog.learningtree.com/tag/ui/.

comments powered by Disqus

Featured

Subscribe on YouTube