Updated 2010/04/12 3:30P EST... added notes for configuring IIS on pre-IIS7 machines
Updated 2010/04/01 7:30P EST... left out the web.config section changes accidentally
ASP.NET Routing is a mechanism for 'routing' URLs that aren't so nice
or friendly to other parsing or organizational mechanisms. Typically to date we've seen routing
in ASP.NET MVC applications, or something similar for general IIS apps using
IIS URL Rewriting.
.NET 3.5 is straight up is fairly awkward to setup simple web routes for traditional web forms applications.
.NET 4.0 has web forms routes
baked in by default.
URL routing is wonderful for SEO. Developers quickly become enamored with
the SEO compliant, 'friendly' URL mechanism. For example, something like "http://www.devfish.net/fullblogitemview?blogid=1072" is not as SEO friendly
or pretty or user friendly as "http://www.devfish.net/blogitem/implementing urlrouting in existing aspnet35 applications". Naturally
I was extolling the virtues of MVC2 and .NET 4.0 Webforms and such. At that point, an attendee asked me how
to implment URL routing into their existing ASP.NET 3.5 SP1 VB Webforms Application.
Why would the attendee want to url routing in .NET 3.5 SP1 webforms? Wouldn't MVC or .NET 4.0 have been a better route?
Technically sure, but it didn't make sense for them right now. Due to various constraints, moving to MVC or .NET 4 was not a feasible option for this application.
.NET and/or MVC were targets in their future, sure, but just not right now. The customer was targeting implementing some
new functionality inside the 3.5 webforms, and wanted to build pages with URLs that could be carried forward into MVC easily, as well
as providing some SEO type benefits now.
Chris Cavanagh put out a great implementation of URL routing in 3.5 SP1 webforms in VB here.
Naturally I pointed the customer to that and said "have fun". The next day the customer emailed me with basically "great, a complete website
doing routing, but how do I integrate that into my site?". So I thought I'd spell out for ya'll the steps I had them take to implement
Cavanagh's routing into an existing ASP.NET 3.5 SP1 application. The "routing implemented" files can be found at http://www.devfish.net/downloads/files/VBASPNET35RoutingImplemented.zip .
Step 1: Get the goodies -- Go get Cavanagh's VB webforms example from http://chriscavanagh.wordpress.com/2009/01/20/aspnet-routing-in-vbnet/.
We're going to steal, er ah liberate, er ah, reuse some/all of his goodies into our existing app. Extract it out into a folder somewhere.
Step 2: Reference it -- [Add Reference] via the Visual Studio Add Reference Dialog, for System.Web.Routing and System.Web.Abstractions. Those namespaces are necessary to support our routing
implementation.
Step 3: Liberate the routables -- copy in the RoutablePage.vb, RoutingHander.vb, WebFormRouteHandler.vb from Cavanagh's stuff to your project. If
you are working in ASP.NET Web Site and not an ASP.NET project type, these files would go into the App_Code directory.
Step 4: going global -- If there's not a global.asax file in the project,
add a global.asax file
Step 5: global namespace -- Add the namespace for System.Web.Routing to the global.asax file. See snippet below
<%@ Application Language="VB" %>
<%@ Import Namespace="System.Web.Routing" %>
<script runat="server">
...
</script>
Step 6 and 7: routes in global.asax -- add your basic routes to your global.asax file by creating a register routes function. You can see the ones I used from the demo project below. Also wire in your
Application_Start handler to call RegisterRoutes with your route table
Private Sub RegisterRoutes(ByVal routes As RouteCollection)
routes.Add(New Route("Welcome", New WebFormRouteHandler("~/Welcome.aspx")))
routes.Add("nameSearch", New Route("community/{searchterm}", New WebFormRouteHandler("~/Search.aspx")))
routes.Add("usergroupSearch", New Route("community/usergroups/{searchterm}", New WebFormRouteHandler("~/UserGroup.aspx")))
routes.Add("usergroupbyid", New Route("community/usergroups/id/{usergroupid}", New WebFormRouteHandler("~/UserGroup.aspx")))
routes.Add("eventsSearch", New Route("community/events/{searchterm}", New WebFormRouteHandler("~/CommunityEvents.aspx")))
routes.Add("eventsbyid", New Route("community/events/id/{eventid}", New WebFormRouteHandler("~/CommunityEvents.aspx")))
routes.Add("eventsbytype", New Route("community/events/type/{eventtype}", New WebFormRouteHandler("~/CommunityEvents.aspx")))
routes.Add("eventsbydaterange", New Route("community/events/daterange/{daterange}", New WebFormRouteHandler("~/CommunityEvents.aspx")))
End Sub
Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
RegisterRoutes(RouteTable.Routes)
End Sub
Step 8: modify your web.config to support routing in the system.web and system.webServer sections
<system.web>
<httpModules>
...
<add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
</httpModules>
<system.webServer>
...
<modules>
...
<add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
</modules>
Step 9: setup a test page to call some routes in -- Here we'll use a pretend events page as our handler and slap them
into welcome.aspx
community/events/{searchterm} - search events for anything with searchterm in it - <a href="community/events/sql server">community/events/sql server</a>
community/events/id/{eventid} - search any event ids exact or patially matching - <a href="community/events/id/SFL123">community/events/id/SFL123</a>
community/events/type/{eventtype} - list upcoming events of this type - <a href="community/events/type/silverlight">community/events/type/silverlight</a>
community/events/daterange/{daterange} - list events in this date range - <a href="community/events/daterange?start=2010-02-11&end=2010-02-14">community/events/daterange?start=2010-02-11&end=2010-02-14</a>
Step 10: process the routes in the receiving page - in this case its "communityevents.aspx" - pull the key/value pairs out
of the routing info, see what they key is, process any query strings, and have fun
_out.Append(String.Format("# of search terms = [{0}]<br/>", RequestContext.RouteData.Values.Count()))
For _ii As Integer = 0 To RequestContext.RouteData.Values.Count() - 1
_out.Append("routedata #" & (_ii + 1))
_out.Append("<br/>")
Dim _key As String = (RequestContext.RouteData.Values.Keys(_ii))
Dim _value As String = RequestContext.RouteData.Values.Values(_ii)
_out.Append(String.Format("[{0}]=[{1}]", _key, _value))
_out.Append("<br/>")
If (_key = "searchterm") Then
_searchterm = _value
ElseIf (_key = "eventid") Then
_eventid = _value
ElseIf (_key = "eventtype") Then
_eventtype = _value
End If
'special logic
If (_searchterm = "daterange") Then
_daterange = String.Format(String.Format("{0} to {1}", Request.QueryString("start"), Request.QueryString("end")))
End If
Next
_out.Append(String.Format("general search: anything with [{0}] in it<br/>", _searchterm))
_out.Append(String.Format("event group by id: id matching [{0}]<br/>", _eventid))
_out.Append(String.Format("event group by type: id matching [{0}]<br/>", _eventtype))
_out.Append(String.Format("events in daterange [{0}]", _daterange))
Step 10: if you are using a version of IIS lower than 7.0 you need to setup a 'wildcard mapping'. see this kb for details...
Happy routing. Hopefully this will sustain you until you can get over to .NET 4.0
or get a good look at ASP.NET MVC2.