URL Routing with ASP.NET 4 Web Forms (VS 2010 and .NET 4.0 Series)

[In addition to blogging, I have recently been using Twitter to-do quick posts and share links. You can follow me on Twitter at: www.twitter.com/scottgu (@scottgu is my twitter name)]

This is the eighth in a series of blog posts I’m doing on the upcoming VS 2010 and .NET 4 release.  Today’s post covers a cool new runtime feature in ASP.NET 4 – which is the ability to use URL routing with Web Forms based pages.

What is URL Routing?

URL routing was a capability we first introduced with ASP.NET 3.5 SP1, and which is already used within ASP.NET MVC applications to expose clean, SEO-friendly “web 2.0” URLs.  URL routing lets you configure an application to accept request URLs that do not map to physical files. Instead, you can use routing to define URLs that are semantically meaningful to users and that can help with search-engine optimization (SEO).

For example, the URL for a traditional page that displays product categories might look like below:

     http://www.mysite.com/products.aspx?category=software

Using the URL routing engine in ASP.NET 4 you can now configure the application to accept the following URL instead to render the same information:

     http://www.mysite.com/products/software

With ASP.NET 4.0, URLs like above can now be mapped to both ASP.NET MVC Controller classes, as well as ASP.NET Web Forms based pages.

Mapping URLs using ASP.NET MVC

The URL Routing engine introduced with ASP.NET 3.5 SP1 provides a powerful way to handle incoming URLs.  Typically you write code as part of application startup to register/map URLs that match a specific URL format to code handlers. 

Below is an example of how you can use ASP.NET MVC today to map the /products/software URL to a controller class called “Products” that has an action method named “Browse”:

step1

The first “products-browse” parameter to the MapRoute() helper method above is a friendly name for the route.  The second “products/{category}” parameter is the URL filter that matches the /products/software URL – and which treats the second segment of the URL as a parameter value called “category”.  This parameter will then be passed to the ProductsController’s Browse() action method to process.

Mapping URLs using ASP.NET Web Forms

ASP.NET 4.0 now allows you to also use the URL Routing engine to map URLs to ASP.NET Web Forms pages as well as ASP.NET MVC Controllers. 

Below is an example of how you can use the new MapPageRoute() helper method in ASP.NET 4.0 to map the /products/software URL to a “Products.aspx” page that lives immediately under the application root directory:

step2

The first two parameters to the MapPageRoute() helper are the same as in MapRoute(). The first parameter provides a friendly name for the route, and the second specifies the URL format to match.  The third parameter, though, points to a Products.aspx page to handle the URL instead of a controller class.  You can optionally specify additional parameters to MapPageRoute() that take advantage of features like “route constraints” and provide “default values for parameters” just like you can with ASP.NET MVC based route registrations.

Within the Products.aspx page you can then write code like below that uses the new Page.RouteData property in ASP.NET 4.0 to retrieve the “category” parameter value mapped using the /products/{category} URL filter, and then databind the category products to display them:

step3

In addition to programmatically accessing incoming route parameters using code like above, you can also take advantage of the new declarative <asp:routeparameter> control with any ASP.NET DataSource control to declaratively bind a value from a route as well.  For example, below we are using a <asp:routeparameter> statement to bind the select statement’s @category parameter from the /products/{category} parameter in the URL route:

step4

Retrieving URLs within an ASP.NET Web Form

The URL routing engine in ASP.NET can be used to both map incoming URLs to code handlers, as well as be used to programmatically generate outgoing URLs using the same mapping registration logic. 

For example, above when we mapped the /products/{category} URL we gave it a “friendly name” of “products-browse”.  This allows us to now also use the new Page.GetRouteUrl() helper method to lookup the route within the URL routing system, optionally specify parameters to it, and then retrieve an actual URL that it maps back to.  For example, the below code would retrieve a URL value of “/products/software”:

step6 

You can access the above helper method within either your code-behind file or within your .aspx markup. 

There is also now a Response.RedirectToRoute() set of methods that you can use to redirect users to a route (regardless of whether it is a MVC or Web Forms handled one) and optionally pass parameters to it.

Handling PostBack Scenarios

URL Routing with ASP.NET 4.0 fully supports postback scenarios.  The <form runat=”server”> control will automatically emit the same URL that caused the page to be rendered.  For example, if you access a page with a /products/software URL then any server-side <form runat=”server”> control within it would render out a <form action=”/products/software”> HTML element back to the client – which means that any postback scenarios that happen on the page will preserve the original URL. 

This makes supporting clean, SEO friendly, URLs easy with Web Forms and postback scenarios – and avoids some of the tricks people need to use today when using URL rewriting modules to achieve similar effects. 

Summary

ASP.NET 4.0 makes it easy to implement clean, SEO friendly, URLs using both ASP.NET MVC and now ASP.NET Web Forms (you can also have applications that mix the two). 

The URL routing engine makes it easy to register URLs of any shape or format and map them to any handler you want.  Because the URL routing engine can be used for both mapping incoming URLs as well as generating outgoing URLs, you can at a later point change the URL mappings  and not have to modify any page or controller specific code to reflect them – which makes building SEO optimized applications much easier.

Hope this helps,

Scott

70 Comments

  • It's great to see the routing features also fully enabled for Webforms too. This can spice up some "legacy" apps quickly and make them more SEO-friendly.

  • Ah... nice, now Web forms can be more SEO optimized. Thanks

  • Really nice feature for ASP.NET 4.0. Would there be perfromance hit for each incoming request? I can see that you have routing code inside Application_Start() event handler, which actually fires only once when ASP.NET application is started, so I think performance should not be an issue, what say ? Also can I have multiple routes.MapPageRoute() for different URLs inside RegisterRoutes() method ?

    Regards,
    abhi

  • Very useful thanks - and nice to see you back posting to your blog again - I guess you've been busy with developing 2010, your world tour :) and the new baby! How do you do it all??

  • Great post! Thanks.
    I really wonder how to use to new routing engine in WebForms.
    Your tutorials are great. Thanks.

  • @abhi,

    >>>>>>>> Really nice feature for ASP.NET 4.0. Would there be perfromance hit for each incoming request? I can see that you have routing code inside Application_Start() event handler, which actually fires only once when ASP.NET application is started, so I think performance should not be an issue, what say ? Also can I have multiple routes.MapPageRoute() for different URLs inside RegisterRoutes() method ?

    There is some performance overhead for URL routing - but in general it is pretty fast. The actual route registration is done only once at app startup time - the routetable is then cached and reused across multiple requests.

    You can definitely map multiple routes - in fact as many as you need.

    Hope this helps,

    Scott

  • Awesome, have missed this previously in webforms. Quick and easy to implement - great stuff.

  • This is really great! Especially the Postback scenario. Really looking forward to ASP.NET v4.0.

  • That’s really nice feature but Scott it seems that we should determine the routing strategy at early stage in the application development. I mean if I want to change a classic web application with intensive use of query strings I could not just register routes and everything is fine. The routes parameters is not tied with query string parameters so I need to change all the Request.QueryString logic to Page.RouteData. Is it possible to couple the route parameters with query string parameters?
    Thanks

  • Another intresting post - thanks Scott!

  • Why does the mechanism not use HttpContext.RewritePath(url)?
    Then developers can still use Request.Querystring["category"] as normal.

  • Just to echo @IsToFix, it would be very cool if there was an article on common methods to upgrade an existing legacy ASP.NET site to accommodate the routing features of .NET 4.

    Thanks for another great article, Scott. I wish your blog was updated more often - maybe you could clone yourself? ;)

  • Hi Scott,

    When can we get a sniff of Beta 2. Will it be days, weeks or months?

  • Hi Scott,
    These look like great little additions to routing for WebForms, but will there be any additional help for those using routing but also the breadcrumb and menu controls?

    Let's say I've defined a route for a page showing a thread in a forum like this: forum/{forumid}/{threadid}/{postid}

    If a user is viewing a post in the forums, will the breadcrumb control be route-aware enough to output, e.g. Forums > This Forum > My Thread > Title Of Post with each crumb hyperlinked as you get with standard non-routed sitemaps?

    Thanks, Dan

  • Nice feature,
    So Scott this is something what we use to accomplish with URLRewriting.Net in ASP.Net 2.0 ?

    Thanks

  • 1. Twitter sucks.

    2. Can you use more Route Parameters, something like below?
    routes.MapPageRoute(
    "products-browse",
    "products/{category}&{filter}&{daterange}"
    "~/Products.aspx");

  • As you know, many companies are blocking access to Twitter. Would you copy your tweets somewhere on your blog?

  • Great feature, really easy to implement. Thanks Scott & ASP.NET Team

  • Really good feature dude. Thanks for sharing.

  • Can you do something like adding a route for "/{path}" to direct all requests to a particular aspx page with the requested url as a parameter? Our app currently uses a custom error handler on 404 and 403 for that purpose and it's pretty hacky code, but the urls we use don't map terribly cleanly to a fixed set of /whatever prefixes for legacy reasons.

  • Hey Now Scott,

    Great News! This sure makes building SEO optimized applications much easier.

    Thx 4 the info,
    Catto

  • "The control will automatically emit the same URL that caused the page to be rendered" = great!!, just greeeeeeatt.

  • quick question: For IIS6 do we need to add a file extension in the URL, like MVC routing?, can ASP.NET 4 + IIS6 tell the difference between a page and a folder.? Thanks

  • Hi Scott,

    I really love this.
    How can I use routes with localization?

  • Its nice to see URL routing feature in VS 2010. I feel its kinda same as ASP MVC.

    Thanks for sharing Scott!

  • Its great to see that the URL Routing is being included with Web Forms.
    I always had a headache with URL rewriting and shared hosting environment.
    Good job guys.

  • Great and easy to use feature! I think I would defer my application upgrades till 4.0 is out.

  • It's cool but I think it's hard to use, because in real project , there are many pages, and all the logic must be placed in global.asax ,even in a single function, RegisterRoutes must be a very very long function. Secondary, pages are changing, we must update the global.asax very frequently.
    I think if the logic could be placed in every individual pages, it will be much more practical.

  • @IsToFix,

    >>>>>>> That’s really nice feature but Scott it seems that we should determine the routing strategy at early stage in the application development. I mean if I want to change a classic web application with intensive use of query strings I could not just register routes and everything is fine. The routes parameters is not tied with query string parameters so I need to change all the Request.QueryString logic to Page.RouteData. Is it possible to couple the route parameters with query string parameters?

    You could use URL Rewriting and the IIS URL Rewriting module that you can get for free using the Microsoft Web Platform Installer. It allows you to rewrite URLs on the way in - in which cases your pages could still use querystrings and program against those.

    The downside with this, though, is that you are rewriting URLs as opposed to mapping them - and so outgoing URLs within your pages will by default still have querystrings and such in them - since the pages don't know about the origional URLs used on the way in (since as far as they are concerned the "real URL" is the one with the querystring). One nice thing about URL routing is that it allows you to avoid this and have a clean mapping.

    Hope this helps,

    Scott

  • @Prabir,

    >>>>>>> But wat if someone does access www.mysite.com/products.aspx

    You'd want to make sure people only come in via the published URLs you send them too. You could write code to block people accessing Products.aspx directly - although in general I'd probably just recommend not publishing those URLs.

    Hope this helps,

    Scott

  • @Graham,

    >>>>>>> Why does the mechanism not use HttpContext.RewritePath(url)?

    Mostly so that instead of re-writing the URL you are mapping it - which means that things like the element within pages output the origional URL instad of the rewritten one. This also makes it cleaner to programmaticlaly refere to routes and generate URLs on the way out as well.

    Hope this helps,

    Scott

  • @Ryan,

    >>>>>>> Secondly, can we use URL routing at subdomain level as well? For instance; route http://vp1.example.com to ~/vp1.aspx or even http://{area}.example.com/{page}.aspx to ~/{area}/{page}.aspx?

    I think you can do the sub-domain routing as well. There are also ways at the IIS level to-do URL rewriting such that you map multiple host header domains to one physical site/application which I think would allow you to achieve what you are after as well.

    Hope this helps,

    Scott

  • @Elangovan,

    >>>>>>>> Can we have URLs with both querystrings and Routed URL combined to form one URL?

    Yes - you can definitely mix both routing and querystrings if you want.

    Hope this helps,

    Scott

  • @Dave R,

    >>>>>>> Thanks for another great article, Scott. I wish your blog was updated more often - maybe you could clone yourself? ;)

    I'm working to update it more often! I've done at least 13 posts the last 6 weeks which is a start :-) My goal is to try and get to 2-3 posts a week going forward.

    Hope this helps,

    Scott

  • @Anton,

    >>>>>>> When can we get a sniff of Beta 2. Will it be days, weeks or months?

    It isn't too far off now - stay tuned :-)

    Thanks,

    Scott

  • @Dan,

    >>>>>>>> These look like great little additions to routing for WebForms, but will there be any additional help for those using routing but also the breadcrumb and menu controls?

    The good news is that you can use routing either separately or together with the sitemap system and menu controls. Just define a sitemap file that contains routes and their relationships and you can use the sitemap API and associated controls against it.

    Hope this helps,

    Scott

  • @Dan,

    >>>>>>>>> 2. Can you use more Route Parameters, something like below?

    >>>>>>>>> routes.MapPageRoute(
    >>>>>>>>> "products-browse",
    >>>>>>>>> "products/{category}&{filter}&{daterange}"
    >>>>>>>>> "~/Products.aspx");

    Yep - you can definitely have any number of parameters in the route. You can also specify default values for each parameter as well.

    Hope this helps,

    Scott

  • @Stuart,

    >>>>>>>>> Can you do something like adding a route for "/{path}" to direct all requests to a particular aspx page with the requested url as a parameter? Our app currently uses a custom error handler on 404 and 403 for that purpose and it's pretty hacky code, but the urls we use don't map terribly cleanly to a fixed set of /whatever prefixes for legacy reasons.

    Yes - you can specify wildcard map routes. You can also order routes so that they are evaluated in order. This would allow you to register a final wildcard route that will be called if all other routes fail - in which case you could do a custom page for 404 and 403 scenarios.

    Hope this helps,

    Scott

  • @Arthur,

    >>>>>>>>> I am also curious if the following request would work in a non MVC-based Web App: www.mysite.com/.../software=Utilities ?

    Yes - you could definitely support that with both a MVC and WebForms based application.

    Hope this helps,

    Scott

  • @griffonwrath,

    >>>>>>>> quick question: For IIS6 do we need to add a file extension in the URL, like MVC routing?, can ASP.NET 4 + IIS6 tell the difference between a page and a folder.? Thanks

    Here is a good page to read that walksthrough how to enable this on IIS6: http://www.asp.net/LEARN/mvc/tutorial-08-cs.aspx This works for both MVC and WebForms based application with ASP.NET 4.0.

    Hope this helps,

    Scott

  • when i install VS 2010 i see more bug
    1. when i use it . it is very very slow and lazy so my lot of time are waste
    2. this application are automatically closed without error
    3. Very very Visual How to get Simple like a 98 theme Visual Studio.

  • Actually it's possible to use System.Web.Routing for web forms and even ajax handlers since 3.5SP1. For example, with NReco framework routing configuration looks like:


    ~/templates/generated/PageForm.ascx



    But it's nice that .NET 4.0 now contains all required classes for WebForms routing.

  • Wonderful new feature. Thanks.

  • Great feature.
    I have a question: can route entries be defined in a file (in XML format for example) outside the code, then route engine will load the definitions automatically? I believe that this will make the code cleaner and it will be much easier to maintain the routes data too.
    It would be great if we have the visual designer for route entries too. :)

  • Nice Features!

    Thanks for the posts

  • Take that MVC! Can we please throw MVC in the trashcan now

  • I wonder how this gonna affect the web part personalization and the paths stored in aspnet_Paths table? this can be helpful for dynamic pages portal

  • Hi Scott,

    Can routes be defined in a config file and reinitalized once it is updated (to avoid updating code and restarting the app domain) ty.

  • Thanks great features:)

  • this is a great improvement on seo. thanks!

  • Currently PreviousPage throws an exception when using routing, has that been fixed?
    Currently, if you want security enabled in web.sitemap, you must use physical paths, and manually create the actual links, is that still necessary?

  • Is there anything in the web.config that needs to be configured? i tried this in development and it doesnt seem to be working.

  • Gr8 feature, URL re-writing always seems complex to me, this feature is really cool :)

  • Great article!!..always felt a complex feature to understand.

  • Handling PostBack is very good

  • Hi Thanks for nice article.
    I have small doubt, for example I have 2 folder in my asp.net project
    1. good
    2. bad
    under this few aspx pages are there, whenever I access pages from this folder, in browser url it should shows that folder name only like calling http://localhost/good/page1.aspx -> it need to show http://localhost/good, if I call page2.aspx or pageN.aspx in url it must show http://localhost/good, also same way in bad folder too. how can I do this? could you help me pleaseeeeeeeeee?? :)

    Thanks

  • Hi Scott,

    Everything I've seen recently is about rewriting urls to map dynamic handler I would like to remap urls to the static file handler.

    For example I would like to be able to map any incoming url like "/styles/{version}site.css" to "/styles/site.css" and have it go through just as if the original request was for "/styles/site.css" (meaning I want to be able to use IIS 7 Static HttpCompression and have "styles/site.css" compressed once and cached)

    The reason for the version number in the urls is so i can put a far future expires header on my static content, but simply change the url version number anytime i want the browsers to download a modified version.

    It seems like this should be possible but any attempt I've made using Context.RewritePath() or Server.TransferRequest() have issues.

    Using Context.RewritePath('/styles/site.css') returns the proper file but IIS then treats the request as dynamic and won't use the static HttpCompression.

    Do you know the correct way I should be doing this or can you recommend a forum that might be able to help?

  • Pretty much all of my querystring URLS are based on the database numeric ID. I wonder if this could be used so that a request for:

    (/products/{category})
    /products/software

    could be mapped to:

    /products.aspx?CatID=123
    where "123" is the integer ID for "Software" in the "Categories" table of my database.

    ? :)

  • The routing seems the same as the current MVC (1.0) routing that we use... i wish instead of the global.asax we could define these routes in a config file as well.

  • I would like to use URL Routing but I am trying to understand if it will work with below scenario.

    Our URL's pass a unique ID for each record and we have thousands of them and growing.
    http://www.mydomain.com/Products.aspx?id=1234567xyz&Category=Work
    http://www.mydomain.com/Products.aspx?id=9038472abc&Category=Home

    How would you handle these Dynamic parameters in RUL Routing? Do I need to manually create an entry in the global.aspx for each record or could this be done Dynamically?

    Thank you

  • ps: my url's did not show up correctly in the above post find them below.

    /Products.aspx?Id=12345&Category=personal
    /Products.aspx?Id=52309&Category=work
    /Products.aspx?Id=39012&Category=personal

    How would you handle these Dynamic parameters in RUL Routing? Do I need to manually create an entry in the global.aspx for each record or could this be done Dynamically?

    Thank you

  • I have the URL Routing working with the VS 2010 .NT 4.0 Beta 2.

    Is it possible to have the same WebForm being loaded by the URL Routing (RouteData) and also the old ways with QueryString parameters in the URL?

    i.e.

    http://www.mysite.com/Books/456
    or
    http://www.mysite.com/Books.aspx?id=456

    The reason I ask is because we have thousands of links that have been given out to users and we do not want to break the current links.

    Thanks

  • ps: links did not show correctly above:

    "http://www.mysite.com/Books/456"
    or
    "http://www.mysite.com/Books.aspx?id=456"

  • This works great when I am debugging in Visual Studio but when I deploy to my local IIS (Win 7, IIS 7.5) it just gives me a 404 error. What is the problem?

  • I am also having the error when I deploy the website using URL Routing for WebForms. It works on my development machine but not on the server running IIS. I have installed the .NET 4.0 Full Distribution install.

    Any ideas?

  • Great post! Thanks. Can MapRoute and MapPageRoute coexist in one application? I cannot make MapPageRoute work if MapRoute is not commented.

  • MapRoute and MapPageRoute actually can be co-existed. The 404 error I got before was caused by a "." in routeUrl.

    I want to immigrate from UrlRewrite to route because route can generate URL easily. I want to keep my old page URL such as "product/11.aspx" or "product/11.html".

    /product/{id}.aspx // this does not work
    /product/{id}/page.aspx //this line works

    The "." is a reserved character in regular expression and I believe it causes the problem.

    I tried /product/{id}%2Easpx and it does not work either.

    How can I make "product/11.aspx" work using MapPageRoute?

  • I have figured out the problem.

    MapPageRoute need to be put first. MapRoute cannot be registered first if using product/{id}.aspx in MapPageRoute.

  • I got the http error 404 problem too. I finally figured it out by spending 2 hours. My problem is that VS2010 was installed before IIS 7.5. After run

    %windir%\Microsoft.NET\Framework\v4.0.21006\aspnet_regiis.exe -i

    The problem is gone.

  • Hi Scott, great post, i used web forms routing on an asp.net 3.5 c sharp web forms project I was working on. All went great I thought yipee I don't need to use a URL rewriter my urls mapped fine to the underlying physical files. Then lo and behold my website went live and after 2 months I see that google won't index my site even tho it has good backlinks and good content, i have used the iis 7 seo tool and that reports no errors, I have done everything from submitting a sitemap and
    a robot.txt file. I just hAve a hunch maybe the google crawler bot doesn't like web forms routing, I could be wrong but then again I've never had this problem on any other site but this is the first time I'm using web forms routing. Any ideas?

Comments have been disabled for this content.