Using Routing With WebForms

UPDATE: I updated the sample to work with the final version of ASP.NET Routing included with ASP.NET 3.5 SP1. This sample is now being hosted on CodePlex.

Download the demo here

In my last post I described how Routing no longer has any dependency on MVC. The natural question I’ve been asked upon hearing that is “Can I use it with Web Forms?” to which I answer “You sure can, but very carefully.”

Being on the inside, I’ve had a working example of this for a while now based on early access to the bits. Even so, Chris Cavanagh impressively beats me to the punch in blogging his own implementation of routing for Web Forms. Nice!

One of the obvious uses for the new routing mechanism is as a “clean” alternative to URL rewriting (and possibly custom VirtualPathProviders for simple scenarios) for traditional / postback-based ASP.NET sites.  After a little experimentation I found some minimal steps that work pretty well:

  • Create a custom IRouteHandler that instantiates your pages
  • Register new Routes associated with your IRouteHandler
  • That’s it!

He took advantage of the extensibility model by implementing the IRouteHandler interface with his own WebFormRouteHandler class (not surprisingly my implementation uses the same name) ;)

There is one subtle potential security issue to be aware of when using routing with URL Authorization. Let me give an example.

Suppose you have a website and you wish to block unauthenticated access to the admin folder. With a standard site, one way to do so would be to drop the following web.config file in the admin folder...

<?xml version="1.0"?>
<configuration>
    <system.web>
        
        <authorization>
            <deny users="*" />
        </authorization>

    </system.web>
</configuration>

Ok, I am a bit draconian. I decided to block access to the admin directory for all users. Attempt to navigate to the admin directory and you get an access denied error. However, suppose you use a naive implementation of WebFormRouteHandler to map the URL fizzbucket to the admin dir like so...

RouteTable.Routes.Add(new Route("fizzbucket"
  , new WebFormRouteHandler("~/admin/secretpage.aspx"));

Now, a request for the URL /fizzbucket will display secretpage.aspx in the admin directory. This might be what you want all along. Then again, it might not be.

In general, I believe that users of routing and Web Form will want to secure the physical directory structure in which Web Forms are placed using UrlAuthorization. One way to do this is to call UrlAuthorizationModule.CheckUrlAccessForPrincipal on the actual physical virtual path for the Web Form.

This is one key difference between Routing and URL Rewriting, routing doesn’t actually rewrite the URL. Another key difference is that routing provides a mean to generate URLs as well and is thus bidirectional.

The following code is my implementation of WebFormRouteHandler which addresses this security issue. This class has a boolean property on it that allows you to not apply URL authorization to the physical path if you’d like (in following the principal of secure by default the default value for this property is true which means it will always apply URL authorization).

public class WebFormRouteHandler : IRouteHandler
{
  public WebFormRouteHandler(string virtualPath) : this(virtualPath, true)
  {
  }

  public WebFormRouteHandler(string virtualPath, bool checkPhysicalUrlAccess)
  {
    this.VirtualPath = virtualPath;
    this.CheckPhysicalUrlAccess = checkPhysicalUrlAccess;
  }

  public string VirtualPath { get; private set; }

  public bool CheckPhysicalUrlAccess { get; set; }

  public IHttpHandler GetHttpHandler(RequestContext requestContext)
  {
    if (this.CheckPhysicalUrlAccess 
      && !UrlAuthorizationModule.CheckUrlAccessForPrincipal(this.VirtualPath
              ,  requestContext.HttpContext.User
              , requestContext.HttpContext.Request.HttpMethod))
      throw new SecurityException();

    var page = BuildManager
      .CreateInstanceFromVirtualPath(this.VirtualPath
        , typeof(Page)) as IHttpHandler;
      
    if (page != null)
    {
      var routablePage = page as IRoutablePage;
      if (routablePage != null)
        routablePage.RequestContext = requestContext;
    }
    return page;
  }
}

You’ll notice the code here checks to see if the page implements an IRoutablePage interface. If your Web Form Page implements this interface, the WebFromRouteHandler class can pass it the RequestContext. In the MVC world, you generally get the RequestContext via the ControllerContext property of Controller, which itself inherits from RequestContext.

The RequestContext is important for calling into API methods for URL generation. Along with the IRoutablePage, I provide a RoutablePage abstract base class that inherits from Page. The code for this interface and the abstract base class that implements it is in the download at the end of this post.

One other thing I did for fun was to play around with fluent interfaces and extension methods for defining simple routes for Web Forms. Since routes with Web Forms tend to be simple, I thought this syntax would work nicely.

public static void RegisterRoutes(RouteCollection routes)
{
  //first one is a named route.
  routes.Map("General", "haha/{filename}.aspx").To("~/forms/haha.aspx");
  routes.Map("backdoor").To("~/admin/secret.aspx");
}

The general idea is that the route url on the left maps to the webform virtual path to the right.

I’ve packaged all this up into a solution you can download and try out. The solution contains three projects:

  • WebFormRouting - The class library with the WebFormRouteHandler and helpers...
  • WebFormRoutingDemoWebApp - A website that demonstrates how to use WebFormRouting and also shows off url generation.
  • WebFormRoutingTests - a few non comprehensive unit tests of the WebFormRouting library.

WARNING: This is prototype code I put together for educational purposes. Use it at your own risk. It is by no means comprehensive, but is a useful start to understanding how to use routing with Web Forms should you wish. Download the demo here.

Technorati Tags: ,,

What others have said

Requesting Gravatar... Tim van der Schaaf Mar 11, 2008 6:44 PM
# re: Using Routing With WebForms
Hi Phil, thanks for the interesting posting. We are currently looking into Url Rewriting on an ASP.Net 2.0 based website. After reading this post I am considering using the Routing engine as it seems a much nicer, cleaner solution. So the question is, can we use the required dll's with ASP.Net 2.0?

Cheers,
Tim
Requesting Gravatar... Vijay Santhanam Mar 11, 2008 11:09 PM
# re: Using Routing With WebForms
Hi Phil,

Great code sample. Luv your work.

Just today I was trying to mimic an MVC-ish pattern with url rewriter (like subtext), http handlers and a custom view engine - all in web forms. This could do the job nicely.

Security be damned i say.

-V
Requesting Gravatar... Brian Mar 12, 2008 5:52 AM
# re: Using Routing With WebForms
Phil,

Thanks for this demo. This is truly awesome for those of us using third-party ISAPI tools. I haven't delved into the code too far yet, but I am curious to know if the full url can be accessed. Could I rewrite a subdomain as a folder path?

Thanks.
Requesting Gravatar... Dragan Panjkov Mar 12, 2008 9:08 AM
# re: Using Routing With WebForms
Phil,
there is a typo in code snippet posted in this post, inside GetHttpHandler should be CheckUrlAccessForPrincipal instead of CheckUrlAccessForPrincipa. Inside posted source code everything is OK.
Requesting Gravatar... Haacked Mar 12, 2008 3:33 PM
# re: Using Routing With WebForms
@Tim Right now, we only support and test with ASP.NET 3.5. You should try it with 2.0, but I offer no warranties. ;)

@Dragan thanks! Fixed

@Brian no, Routing is specific to an Application. So it handles everything after the ApplicationPath. For subdomain rewriting, you'll still need to use UrlRewriting.
Requesting Gravatar... Denny Ferrassoli Mar 13, 2008 1:55 AM
# re: Using Routing With WebForms
Hey Phil,
Thanks for the great example. I implemented your example in a project but had a question. To get the RouteData Values does the page need to be a RoutablePage?

Thanks!
Requesting Gravatar... Tony Mar 24, 2008 8:50 PM
# re: Using Routing With WebForms
How would you pass url segments (routed) to parameters?

/items/47 to itemcalc.aspx?iid=47

?
Requesting Gravatar... Haacked Mar 25, 2008 2:35 PM
# re: Using Routing With WebForms
Hi Tony, you wouldn't. Routing is not Url Rewriting. Instead, you'd pull the values from Route Data. For example, suppose you had a route with the following url pattern:

items/{id}

Which you mapped to ItemCalc.aspx. If you make ItemCalc.aspx inherit from RoutablePage (it's in the code for this article), then you would have access to this.RouteData.Values["id"] in order to get the value.

Does that make sense?
Requesting Gravatar... Anthony Apr 28, 2008 5:29 AM
# re: Using Routing With WebForms
Hi Phil,

URL Routing replace URL Rewriter?
Requesting Gravatar... Anthony Main May 08, 2008 1:03 AM
# re: Using Routing With WebForms
Hey, nice implementation I've implemented it in my latest development framework, only issue Im having is that whist running on VS Dev Server the root url works (i.e http://localhost:1234/) but when using localhost with a wildcard mapping (iis5.1) root url (i.e. http://localhost/) 404's. Event when I have a default.aspx route.

Any ideas?!
Requesting Gravatar... dmitry39 May 15, 2008 11:15 PM
# re: Using Routing With WebForms
Thx, great post. Phil, can i translate and repost it into my Russian blog about asp.net programming (of course with a link to your original post)?

Regards from Russia
Requesting Gravatar... Haacked May 16, 2008 1:17 AM
# re: Using Routing With WebForms
@dmitry39 feel free.
Requesting Gravatar... Ahtesham May 29, 2008 3:03 PM
# re: Using Routing With WebForms
i am new in MVC i download ur example but i trying to run this on viusal studio 2008 professional edition it give me error that

Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.

Requested URL: /Default.aspx

even i have selecte the default as my start up page and WebFormRoutingDemoWebApp as my startup project , am i missing something i just want to know how mvc works
Requesting Gravatar... Marble Wu Jun 13, 2008 10:43 AM
# re: Using Routing With WebForms
Wonderful~~
Requesting Gravatar... alex Jun 14, 2008 4:05 AM
# re: Using Routing With WebForms
thx, is that what i need
:)
Requesting Gravatar... Nguyen thoai Jun 25, 2008 5:28 PM
# re: Using Routing With WebForms
Thank you, it's very nice post :D
Requesting Gravatar... Max Jun 25, 2008 7:31 PM
# re: Using Routing With WebForms
Really helpfull. Thanks a lot :)
Requesting Gravatar... Nick Jul 21, 2008 11:37 PM
# re: Using Routing With WebForms
Phil, Does routing link data to the static physical page? Or can we link the data to a logical page as in URL Rewriting?
Requesting Gravatar... haacked Jul 22, 2008 1:32 AM
# re: Using Routing With WebForms
Nick, routing puts data into the requset context (via the RouteData values dictionary) which you can access from the page. The URL is completely separate from the page.
Requesting Gravatar... dkarantonis Sep 03, 2008 7:13 PM
# re: Using Routing With WebForms
Hi Phil,
very nice article indeed.
Just one quick question. Does url routing work with traditional asp.net 3.5 web sites, or only with asp.net mvc web application projects?
Requesting Gravatar... Marco Sep 11, 2008 12:37 AM
# re: Using Routing With WebForms
Hi Phil,

I've tried to use this and adapted it for Codeplex MVC Preview 5, but it doesn't work anymore. Registering routes works fine, but route.GetVirtualPath() returns null everytime. Are there any breaking changes in this method?

The only change I've made on your sample code is replacing the constructor of HttpContextWrapper2 with that one of HttpContextWrapper because the HttpContextWrapper class doesn't exist anymore (in RoutablePage class).

Thanks,
Marco
Requesting Gravatar... Andrew Feldman Sep 15, 2008 1:53 AM
# re: Using Routing With WebForms
Hi Phil, great blog! I have implemented a routing handler for web forms using the approach you outline here. One problem I am having is that HttpContext.Current.Session is null in the page I construct and route to in the WebFormRouteHandler. Session is not null on ordinary, non routed, pages in my application. I am using .NET 3.5 sp1, I have not used any of the MVC previews. Any insight is appreciated. Thank you!
Requesting Gravatar... AC Oct 12, 2008 11:33 AM
# re: Using Routing With WebForms
Thanks for the code sample. Just a minor point; I didn't find the use of extension methods to be helpful in the example code. No offense, but it muddles the use System.Web.Routing that you're trying to communicate across. It also forces me to load it into Visual Studio which I don't always want to do.
Requesting Gravatar... prabhjot singh Oct 31, 2008 8:10 PM
# re: Using Routing With WebForms
respected sir,

I am new to ASP.NET. I am working on URL routing for last couple of weeks, although i have implemented routing on the static pages in my site, but i get stuck when i have to implement it on dynamic URL's.

eg

If i have to generate url's for the each user profile in my site, then the relative URL which needs to be generated should not contain the query string values such as the user id.

secondly
if i have two pages( home.aspx and profile.aspx) in my site in the same folder eg "logged". The actual Url is mysite/logged/home.aspx.
i want the relative url to be mysite/index, which i have achieved using your code but now when i click on some other page and then when again i hit in the home tab the url displayed is mysite/logged/index which is wrong. The folders name is shown again in the url.

what should i do? hope you understand what i want to achieve.
regards

prabhjot



Requesting Gravatar... LD Nov 09, 2008 3:33 PM
# re: Using Routing With WebForms
Does IIS 5.1 support web form routing?
Requesting Gravatar... Jay Nov 16, 2008 11:01 PM
# re: Using Routing With WebForms
I'm trying to use this on shared host that doesn't allow reflection, and the methods to render a link apparently uses this because they give me error on this. I don't really understand reflection, could someone point out to me what parts in rendering the link that are reflection and how to get around it? Thanks. Hopefully someone still reads this...
Requesting Gravatar... Leigh Nov 25, 2008 6:57 PM
# re: Using Routing With WebForms
How can we get this working in conjunction with the SiteMap? More specifically, how can it be made to work with the dynamic aspect of routing?
Requesting Gravatar... Edmund Dec 03, 2008 4:20 PM
# re: Using Routing With WebForms
It worked fine, till I switched the web project to use the "Local IIS Web Server" instead of the "VS Development Server".

I am using a XP development machine with its local (oldish) IIS 5.1

Is there a way to develop against that IIS version?
What about IIS 6 on a production Windows Server 2003?

Thanks
Requesting Gravatar... Mike Dec 07, 2008 12:33 AM
# re: Using Routing With WebForms - lost Session
I'm having the same problem as Andrew. Everything works great but the pages loose their Session state. Session is fine if I access the page via their full path rather than a route. Any thoughts?
Requesting Gravatar... Timothy Khouri Dec 29, 2008 9:53 PM
# re: Using Routing With WebForms
For those of you who are having the "null SessionState" (or null User, etc) error... see my frustration/solution here: stackoverflow.com/.../asp-net-routing-do-custom...
Requesting Gravatar... Edmund Jan 11, 2009 4:58 PM
# Links on master page
I tried implementing this with MasterPages, where the master page folds the links to other pages (used as a menu). However, Html.Routlink does not exsit on the master page as it is implemented at the page class level.

How to have the link on a master page?

Thanks
Requesting Gravatar... Jeromy Irvine Jan 22, 2009 5:07 AM
# re: Using Routing With WebForms
This is exactly what I needed for a project. Is there any chance that something like this will make it into the framework in the future?

One note, I think there is a bug in the Demo download. HtmlHelper.cs, Line 50, Col 36 passes null rather than the "name" parameter.
Requesting Gravatar... Dmitry Feb 15, 2009 6:38 AM
# re: Using Routing With WebForms
This is exactly what I needed. However, it works great in the Visual Studio built-in server but if I try to run it in II7 (integrated mode) the UriRoutingHandler throws an exception "Cannot create an abstract class."

Thanks,
Dmitry
Requesting Gravatar... Dmitry Feb 15, 2009 7:57 AM
# re: Using Routing With WebForms
I fixed that problem by deriving a handler from UrlRoutingHandler and referencing it.

However, I have another issue now. If the routing does not end with an .aspx extension, I get "Request for principal permission failed." when trying to use PrincipalPermission Demand() authentication using a custom principal.
Requesting Gravatar... Fenster Feb 24, 2009 4:50 AM
# re: Using Routing With WebForms
I have found it as a plugin to download in the internet.
Requesting Gravatar... Mitch Apr 02, 2009 10:41 AM
# re: Using Routing With WebForms
Has anybody tried using routing with native iis7 output caching. It has a setting for varyByQueryString but since the qs is not changing, a page like /product/1 and /product/2 mapped to product.aspx would return the same thing?

Great artice. Thanks,

Requesting Gravatar... Josh Lewis Apr 03, 2009 7:17 AM
# re: Using Routing With WebForms
I have implemented your solution in site that I had already built that uses a lot of ASP.NET AJAX, specifically the ScriptManager control. However, all of my ajax JavaScript is bombing out. The first error I get is 'ASP.NET Ajax client-side framework failed to load'. I have looked all over the web and it appears that many others are having the problem and everyone has a different solution. I get the same errors on VS08 integrated web server and Server 2003 IIS 6.0 with wildcard mapping enabled.

Any thoughts or a push in the right direction would be very much appreciated.

Thanks,
Josh
Requesting Gravatar... Josh Lewis Apr 05, 2009 7:57 AM
# re: Using Routing With WebForms
Just wanted to follow up and say that I got it working with AJAX after finding your comment on Stack Overflow here stackoverflow.com/.../how-to-ignore-route-in-as...

The one comment that I want to make is that it is important to keep the order of your routes in mind else this fix doesn't work.

Thanks for a great post.

Josh
Requesting Gravatar... Eric Jan 15, 2010 12:49 AM
# re: Using Routing With WebForms
I have implemented your solution and find that it works great, with one exception. I load up a RouteCollection using some data from a database to act as a VirtualPathProvider. When the user hits my domain: domain/abc, the abc part is transalted into a querystring value to pull some data.

My issue, is that when the abc becomes a value that wasn't loaded into the RouteCollection, I obviously get errors. How is this handled?

Great post,

Eric
Requesting Gravatar... Saravanan Feb 06, 2010 11:46 AM
# re: Using Routing With WebForms
Thanks. This is really very useful. But one i am getting one problem in using this with Master page. I found that i can't use <%=Html.RouteLink("/Home", "Login")%> in MasterPage. I can use only <%=Html.RouteLink("/Home", "Login")%> in the page inherited from routablepage class. Is that correct? or any other solution to use <%=Html.RouteLink("/Home", "Login")%> in masterpage.

Regards,
Saravanan
Requesting Gravatar... Sarp Feb 06, 2010 11:41 PM
# re: Using Routing With WebForms
I tried several very simple routing sentence tests in my VS 2008 3.5SP1. I could not achieve to run any. I also tested two other sample websites. Both did not worked in my VS.
I downloaded SimpleRoutingTest project from Codeplex, opened and run it in VS 2008 3.5 SP1. Great! it worked.
I have a website where I want to use it. I copied SimpleRoutingTest there. It did not worked in this VS.
I simplified the approach and created a new website in a new empty VS solution and opened SimpleRoutingTest in the solution also. I copied all files except bin, obj and properties from SimpleRoutingTest to website. I added references of Routing and Abstractions to website. Removed SimpleRoutingTest project from solution. (tried both moved / not moved helpers to App_Code). It does not run. What I am missing? What can be solution to run routing in my website?
Requesting Gravatar... Patrick Oliveros Feb 21, 2010 3:15 PM
# re: Using Routing With WebForms
I noticed that the codeplex project is no longer visible. Any fix to the link?
Requesting Gravatar... Stelios Feb 21, 2010 8:24 PM
# re: Using Routing With WebForms
I've only tried url rewriting so far but I'm definitely moving to asp.net routing!
Requesting Gravatar... ztruk_002 Feb 24, 2010 12:08 AM
# re: Using Routing With WebForms
I'd like to see the code, but the link doesn't seem to be working. Any reason?

thx
Requesting Gravatar... vythees Mar 02, 2010 6:16 AM
# re: Using Routing With WebForms
Thanks for your wonderful post.

The demo download page in codeplex is blank.

Thanks again.

Requesting Gravatar... Scott Fraley Apr 14, 2010 3:46 AM
# re: Using Routing With WebForms
Still no fix to the broken link to yer demo eh? :(
Requesting Gravatar... Chicago mover Aug 11, 2010 6:47 PM
# re: Using Routing With WebForms
Thanks for such a great post.
Requesting Gravatar... Sherwin Aug 12, 2010 11:58 AM
# re: Using Routing With WebForms
Anyone has a mirror link for phil's demo?, Anyway thanks Phil I Hope I read it two years ago >.<
Requesting Gravatar... winbeanye Aug 12, 2010 12:01 PM
# re: Using Routing With WebForms
good .thank you
Requesting Gravatar... Richard Everett Sep 09, 2010 11:59 PM
# re: Using Routing With WebForms
Phil,

Thanks for the technique - it really helps us. However we've noticed that on occasion the first call to CreateInstanceFromVirtualPath can take a long while (tens of seconds) to return. During that time we can see a C# compiler process (csc.exe) chewing up 10%-50% of our CPU cycles.

Any thoughts on potential fixes for this issue?
Requesting Gravatar... Gary A. Sep 20, 2010 2:46 AM
# re: Using Routing With WebForms
I realize that this is just a partial solution, but where do you catch the SecurityException? I define my routes in a Global.asax.cs file, but in the real world, I'd probably just redirect the user to a login page. Perhaps I'm missing something in my understanding of this?
Requesting Gravatar... Venkat Dec 14, 2010 2:34 PM
# re: Using Routing With WebForms
Hai,

The download link doesn't not working
Requesting Gravatar... naveenj Dec 14, 2010 6:01 PM
# re: Using Routing With WebForms
Hi Phil,

You removed the download demo? Cannot access it.
Requesting Gravatar... Jayesh Jan 18, 2011 2:23 AM
# re: Using Routing With WebForms
Hi,

I am using URL Routing for display user profiles. I am using master page and child pages. The profile page is a child page and the master page has a login status control. When I login (say user x) through the modal popup which is in the master page itself, i can browse the site with smoothly and reach the routed page. When I log out from the routed page using the login status i get redirected to my home page as required as my login status also is logged out. If i login from this homepage now with another username say y, i get logged in successfully.

The problem is that when I again use the routed to get to the routed page, I get the previous user x still logged in. When i come to homepage I see user y logged in. So I have two sessions working; one in the routed page, and other in the whole of the website.

I will be obliged if anyone can point out the session problem. :)
Requesting Gravatar... Joy Jul 26, 2011 5:37 PM
# re: Using Routing With WebForms
msdn.microsoft.com/en-us/magazine/dd347546.aspx
Requesting Gravatar... victoryans Aug 31, 2011 6:32 PM
# re: Using Routing With WebForms
I just want to asked if there's a workaround in routing using masterpage. I put the links in masterpage (i.e. first link has a href of /products/list and the other link has a href of category/name) if i click the first link it redirect me to the correct url which is http://mysite/products/list but if i click the next link it will redirect me to http://mysite/products/category/name but the link should be http://mysite/category/name
Requesting Gravatar... Javad Oct 19, 2011 10:24 PM
# re: Using Routing With WebForms : Subdomain Routing
Hi phil,
very nice code.
I'm using it in my projects, but now i want route sub domains like
japan.mysite.com, at all {Country}.mysite.com and route this page to Country.aspx
how can i do this.

thanks
javad

What do you have to say?

(will show your gravatar)
Please add 2 and 2 and type the answer here: