About the author

J Sawyer is a developer based in Houston, TX who absolutely loves to write code. After spending 9 years at Microsoft, he moved on to other things and is currently the Lead Developer for the RealTime Data Management team at Logica US. He spends his days building Really Cool Things around StreamInsight and having a blast doing it.

He has been involved with HDNUG, one of the oldest and largest .NET-focused user groups in the US, since its inception in 2001 and has watched it grow from 5-10 technologists meeting around a conference table to a thriving community of over 5000 with regular meeting attendance averaging 100 attendees. He currently serves as the Vice President. You can join him at HDNUG on the second Thursday of every month at the Houston Microsoft office.

He also loves to ride his Yamaha FZ1. And sometimes his Ninja 650. And also his Honday XR-400 dirt bike. But he doesn't code and ride at the same time. That would be bad.

Url Routing in ASP.NET

January 30, 2009 9:16 PM

One of the new features in ASP.NET 3.5 SP1 is Url Routing … it’s the magic behind the pretty, clean url’s that you see with Dynamic Data and MVC. If you dig around a bit, almost all (if not all) of the material that’s out there focuses on using Routing with either MVC or Dynamic Data … I’ve found nada that actually talks about how it can be added to an existing ASP.NET WebForms application. In talks of .NET 3.5 SP1, Url Routing is even ignored some of the time … and if it’s not ignored, it’s barely mentioned in passing. And then there’s the documentation which is, IMHO, pretty lame and the “How To” articles on MSDN are only mildly better.

In spite of (or maybe because of) that, I found myself intrigued by the whole idea of Url Routing. Yes, I had seen it and tweaked it in MVC and Dynamic Data, but I knew that there had to be additional uses for it. So … I set about to build a demo for Houston Tech Fest that showed how to get started with Url Routing, adding it to an existing website that showed some data from Northwind. It’s not a pretty or even really functional app … that’s not the point … and has Url’s that are both plain vanilla and that require query strings. In addition, there was absolutely, positively no consistency between the pages or the query string parameters. I know that doesn’t happen in the real world! ;-)

There was one thing that I did do in the application that I don’t see done frequently; I added a static utility class that built and returned Url’s for the different pages in the app. Again, not something that I typically see, but it is definitely something that can make the maintenance of links and url’s easier and more elegant. Well, maybe not elegant but it sure beats “Find in project”. But then, url’s in the application never change, do they?

If you’re interested, you can find the PPT and the demos (as well as something resembling a script) on my SkyDrive. It’s the same place as the link that I posted the other day for my Houston TechFest presentations. However, I wanted to spend a little more time and explain what’s going on and how it all works.

StaticRoutingHandler

This is what does the work. All you have to do to create a routing handler is to implement the IRouteHandler interface. It’s pretty a simple interface – there’s only 1 method. This takes a url route and then transfers this to a static .aspx page that is configured for the route (1 route, 1 page). Since I needed to pass query strings to the pages, I also do some url rewriting in here. Technically, this is not necessary to pass information to the target page, but remember – I didn’t want to have to spend a lot of time making changes all over the app and changing the pages to no longer require query strings would be more work and get away from the point of the demo (i.e. making it easy). While you do create an instance of the page with Url Routing, the pages in this demo didn’t have any nice properties that encapsulated the query string parameters. No way to do that without url rewriting when the app is expecting to get query strings. It takes the data arguments specified in the route and turns them into query strings, using the name as the query string parameter. Here it is:

public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
    string finalPath = VirtualPath;
    if (requestContext.RouteData.Values.Count > 0)
    {
        List<string> values = new List<string>();
        //Add these to the virtual path as QS arguments
        foreach (var item in requestContext.RouteData.Values)
        {
            values.Add(item.Key + "=" + item.Value);
        }
        finalPath += "?" + String.Join("&", values.ToArray());

    }

    //Rewrite the path to pass the query string values. 
    HttpContext.Current.RewritePath(finalPath);

    var page = BuildManager.CreateInstanceFromVirtualPath(
        VirtualPath, typeof(Page)) as IHttpHandler;
    return page;
}

Configuration

This is where it could potentially get hairy. With MVC and Dynamic Data, it’s pretty easy to do it in the global.asax file since their paths and page names follow a clear and simple convention. Not so with the sample app. So each route/page combination needs to be registered separately because the page names have absolutely no consistency, not to mention the query string arguments. Ewwww … that’ll bloat your global.asax real quick. Since I didn’t like how that was going, I decided that I’d make it configuration-driven. This had the added benefit of allowing you to change the routes, arguments, etc. without redeploying code. I wrote a custom configuration section to handle this; this also makes the config read/write with the API which I thought might be a nice-to-have. So, the section looks like the following:

<StaticRoutes>
  <Routes>
    <add name="AXD" routeUrl="{resource}.axd/{*pathInfo}"></add>
    <add name="CategoryList" routeUrl ="CategoryList" virtualPath="~/CategoryList.aspx"/>
    <add name="ProductList" routeUrl="Category/Products/{C}" virtualPath="~/ProductList.aspx">
      <Restrictions>
        <add name="C" value="\d"/>
      </Restrictions>
    </add>
    <add name="ViewProduct" routeUrl="Product/{Id}" virtualPath="~/ViewProduct.aspx">
      <Restrictions>
        <add name="Id" value="\d"></add>
      </Restrictions>
      <Defaults>
        <add name="Id" value="1"/>
      </Defaults>
    </add>
    <add name="CustomerOrders" routeUrl="Customers/Orders/{Cu}" virtualPath="~/ListOrders.aspx">
    </add>
    <add name="CustomerList" routeUrl="Customers" virtualPath="~/Customers.aspx">
    </add>
    <add name="OrderDetails" routeUrl="Customers/Orders/{Id}" virtualPath="~/OrderDetails.aspx"/>
  </Routes>
</StaticRoutes>

It’s got all of the information that we need to create our routes. Restrictions and Defaults are optional – not every route needs them. You’ll also notice that the “AXD” route doesn’t have any virtual path listed … when there is no virtualPath specified, the StaticRoutingHandler.Configure method will add a StopRoutingHandler rather than the StaticRoutingHandler. The StopRoutingHandler is the only handler (that I could find) that is in the API itself (MVC and Dynamic Data each have their own RoutingHandlers). It tells Routing to simply ignore the request and send it along it’s merry way as if there was no routing configured. The order of the routes in the config file does matter, but that has nothing to do with my code; when the ASP.NET routing framework looks for the handler that a particular url matches, it grabs the first that it finds on the list. So … that’s how you prioritize your routes. The query string parameters are surrounded with curly braces … so “{Cu}” in the CustomerOrders route above would get put in as a query string named “Cu” with the value that appears in that place in the url.

With the configuration, RegisterRoutes, rather than being a mess that looks more like my office desk than code, is clean, simple and sweet. We just need to call a static method on the StaticRoutingHandler class to read the configuration and add the routes.

public static void RegisterRoutes(RouteCollection routes)
{
    routes.Clear();

    StaticRouting.StaticRoutingHandler.Configure(routes);

}

The names (which are required) also allow us to build the Url using the Routing API, rather than having Url’s hardcoded in the application. It’s pretty simple and straightforward; below is one of the more “complex” examples as it builds the RouteValueDictionary with the value for the query string.

public static string GetProductsForCategory(int categoryId)
{

    var values = new RouteValueDictionary();
    values.Add("C", categoryId);

    var path = RouteTable.Routes.GetVirtualPath(
        null,
        "ProductList",
        values);
    return path.VirtualPath;

}

I got a question when I did this presentation about wildcard parameters. I knew about them and how they worked, but somehow didn’t think to play with them in this sample app. First, you can do this (and I mentioned it in the presentation) by adding a wildcard parameter to the route. In our configuration, it would look like the following:

<add name="Wildcard" routeUrl ="Wildcard/{id}/{* params}" virtualPath="~/Customers.aspx"></add> 

It doesn’t have to have a set parameter (id in this case) in the routeUrl; I just put that there as a comparison. Everything else after that goes into a single item called (in this case) “params”. The “id” is exactly as we expect it to be. However, the wildcard doesn’t translate well into query string parameters. Yes, it is named “params”, but the value is everything in the path in the wildcard’s place, including the slashes in the path. So, with the url http://localhost/Wildcard/3/sasdf/asdf/as, the value of “params” is sasdf/asdf/as. Yes, the routing handler will very happily pass this along when it rewrites the url, but doesn’t really seem to make sense in this context. In this case, I’d say that you put each possible query string/route combination in as a different route to make sure that the page gets the parameters it expects the way that it expects them. I might, some time in the future, put some more thought into this and come up with something else, but for right now, I’m happy punting on it for now and just adding a route for each combination.

Tags: ,

Web (and ASP.NET) Stuff

Presentation content posted!

January 28, 2009 6:11 PM

Finally getting caught up on getting my presentation content posted.

First, there’s the “Building your First Cloud Service” that I delivered at the Aggieland .NET User Group and the North Houston .NET User Group.

Next, there are 2 presentations from Houston TechFest: The OWASP Top Ten Review and the ASP.NET Url Routing demo. Enjoy!

Tags: ,

Community | Events

TechFest Sessions

January 23, 2009 7:14 PM

Sessions, that is, that I’m doing or participating in. :-)

First, I’ll be participating in Zain’s session on VIrtual Worlds and Virtual World Evangelism. I’ll only be showing a bit of stuff for a few minutes … really just to showcase some of the things that can be done in Second Life.

Next … the one that I signed up for originally … the OWASP Top Ten. This will review the vulnerabilities on the OWASP Top 10 (duh!), explaining each one and explaining how the .NET (and ASP.NET) platform can help you mitigate these vulnerabilities. It’s been very well received when I’ve done it on other occasions and it’s security … something that I’m pretty passionate about.

Finally … this just in and HOT off the presses (as in, I just finished writing the demo!) … I’ll be doing a session on add Url Routing (from Fx 3.5 SP1) to existing applications. It’s already the magic goo behind MVC and Dynamic Data … but there’s no reason that you can’t use it for your current apps to provide clean, purty Urls in your applications. I’ll start at the very beginning with an ASP.NET app with all kinds of ugly Urls - they grew organically, so there’s no consistency in the names which, of course never happens in the Real World(tm). Then I’ll add routing in step by step by step … culminating in adding in a configurable (as in, from the web.config), reusable routing component for adding to these types of applications. Should be pretty cool. I’ll post the code for this when I’m done and I’m certainly using this in CSK.

So … with that, I’m outta here and I’ll see (some of) you tomorrow at TechFest!!

Tags: , ,

Community | Events | User Groups

It&rsquo;s been too long &hellip;

January 23, 2009 12:08 PM

Yes, I know. It’s been a while. Well, too long. Holidays and such were BUSY BUSY BUSY. And then … well … I don’t know. But yes, I am still alive and kicking. :-)

Quick update on upcoming stuff:

  • Houston TechFest is tomorrow!! Houston tech community uber-conference is happening after being rescheduled due to Ike. If you haven’t registered, you can still show up … you just won’t get a T-shirt. The whole community evangelism team will be on hand and we’ll also have a ton of kewl stuff to give away … including Rock Band 2 and a Lego Mindstorm robot!!
  • Dallas MSDN Developer Conference is on Monday. This is the very last of the MSDN Dev Con series. There’s still time to register also!
  • South Houston .NET User Group is, after a delay due to (once again) Ike, is getting rolling with their first meeting on February 4th at the Clear Lake City – County Freeman Branch Library. I’ll be speaking there … doing an introduction to unit testing with C#.

So … what’s been happening with me during all this silent time? Besides being busy with work, holidays and all that stuff, the biggest thing was that I had Lasik done. It’s really cool … I’ve gone from not being able to see the big “E” on an eye chart (was just a fuzzy mess) to having 20/15 vision. It’s almost surreal being able to see so well after wearing glasses since 3rd grade and contacts since freshman year of high school. It was quick, easy and, best of all, painless. I was back up and running just fine the very next day. Another thing of not (on a more personal level, that is) is that I finally bit the bullet and upgraded my personal system to an AMD Phenom 9950 Quad Core … with 8 GB of RAM as well. It’s fast. I really don’t know (yet) what to do with all of it …

Finally … for those looking for CSK 3 news … none yet, but keep an eye here. :-)

Tags:

Idle Babbling