home links tools blog about
home

« Huh? What? | Main | Windows Vista Security Flaw? Um... No. »

January 31, 2007

ASP.NET AJAX and Url Rewriting

UPDATE: While the approach listed in this post is still a valid option, Scott Guthrie provide an even clean approach that make this even easier to implement. I've blogged about those improvements and provided a link to his post here.

First of all, thanks to fellow ASPInsider Scott Mitchell for his insanely thorough article on how to configure Url Rewriting with ASP.NET 1.1. What follows is an overview of the additional tweaks I needed to put in place to get Url Rewriting to work SEAMLESSLY with ASP.NET 2.0 and ASP.NET AJAX.

I'm currently involved in building a website that requires a LOT of url rewriting. Initially I didn't plan on having any post-backs, so I pretty much ignored the fact that Url Rewritten pages will post-back, by default, to the 'translated' url. So, if I rewrite:

http://mysite.com/name_of_product_here
to
/pages/products.aspx?id=name_of_product_here

any time a user issues a postback from that page, they'll be posting back to:
http://mysite.com/pages/products.apx?id=name_of_product_here

That's not a huge deal, I guess - unless you really want the urls on your site to be 'hackable' (i.e., you want to treat the urls on your site as a type of navigational interface that end-users can use if they want). Scott Mitchell's Url Rewriting article showed how to deal with that by creating a custom implementation of System.Web.UI.HtmlControls.HtmlForm. The gist was just to override how it rendered its attributes, and strip out the action attribute.

The nice thing too, is that with ASP.NET 2.0 Master Pages, I only had to 'swap out' the standard HtmlForm tags with the tags for my over-ridden/inherited HtmlForm class once. Even better, there was no need to compile my overridden class as I was able to just dump it in the App_Code folder. To reference code in the App_Code folder, you just need to remember that it will be compiled on your server, and output to "App_Code.dll"... which means you can register your own tags like so:

And, hooking that form into my master page was simple, I just had to replace the opening tag:

and closing tag:

Using Scott's method of overriding a form control that doesn't emit an action attribute completely solved my issue with Post-backs and url-rewriting in ASP.NET 2.0. But with ASP.NET AJAX installed and running on some of my rewritten pages (especially coupled with an UpdatePanel), having a blank/default action attribute just wasn't working.

Using Fiddler I could see that my AJAX requests were actually attempting to access: /pages/ - with nothing else specified (i.e. not /pages/products.aspx or anything - clearly something was messed up). Accordingly (since I had a default document set up in the specified location), I was getting ViewStateMac errors/warnings. In other words, my AJAX requests were getting warnings that were 500 errors. The net result though, was that my update panels/ASP.NET AJAX was broken.

Happily, my Url Rewrite Module made use of the following logic to store the 'original' (as in un-rewritten' url). Storing it in Context.Items is a light-weight way to ensure that it sticks through the entire request-response cycle:

Knowing that I had access to the 'pretty' url stored in Context.Items, I just made a minor tweak to the code that Scott provided in his article. The purpose of my tweak was to explicitly set the location of the action attribute - without having to add an 'Action' property or any other thing to my custom class. The entire class is listed below (with it's namespace):

using System;
using System.Web;
using System.Web.UI.HtmlControls;

namespace SSV.Rewrite
{
/// <summary>
/// Summary description for ActionlessForm
/// </summary>
public class RewriteForm : HtmlForm
{
protected override void RenderAttributes(
System.Web.UI.HtmlTextWriter writer)
{
writer.WriteAttribute("name", this.Name);
base.Attributes.Remove("name");

writer.WriteAttribute("method", this.Method);
base.Attributes.Remove("method");

this.Attributes.Render(writer);


string action = Context.Items["Original_Path"] as string;
if(action != null)
writer.WriteAttribute("action", action);

base.Attributes.Remove("action");

if (base.ID != null)
writer.WriteAttribute("id", base.ClientID);
}
}
}


Not much there, as you can see (the whole process was pretty painless). The beauty though is that my rewritten pages are now served up with a rewritten action attribute. So pages now totally post back to their rewritten location, and ASP.NET AJAX works perfectly with my Url Rewriting Scheme. So now I've got the best of everything: url-rewritting or tidying, hackable urls, and ASP.NET AJAX goodness.


Shiny.

TrackBack

TrackBack URL for this entry:
http://www.typepad.com/services/trackback/6a00d8341ce4d453ef00d8341e1f8853ef

Listed below are links to weblogs that reference ASP.NET AJAX and Url Rewriting:

Comments

Oh, thank you! I was previously overriding the Render() method on my master page to fix the action, but it wasn't working with the UpdatePanel. Now I'm back on track...

huteonahtn uehant uehtna ueao u htnueatnh http://www.google.com/search?hl=en&client=firefox-a&rls=org.mozilla%3Aen-US%3Aofficial&hs=pLt&q=url+rewriting+asp.net+ajax+form+action+&btnG=Search

Thanks for this tip. My home grown UrlRewrite is now working perfectly with ASP.NET Ajax.

Great tip. Also overwriting the render to fix the action. Works great now.

Brilliant. I was using both similar methods but couldn't get ajax methods to work with url rewriting. I only had to add the context.items... lines into my exising code to get everything working.

Works with telerik RadAjaxManager as well.

Hi,
The code works great with AJAX. However when I have AJAX as well as POSTBACK events on the same page the code starts giving problems. Can you help me with this??

Great tip. Also overwriting the render to fix the action. Works great now.
thank you

Thanks for this tip. My home grown UrlRewrite is now working perfectly with ASP.NET Ajax.

very good post thank you

Very good post indeed. I will try your solution.

Verify your Comment

Previewing your Comment

This is only a preview. Your comment has not yet been posted.

Working...
Your comment could not be posted. Error type:
Your comment has been saved. Comments are moderated and will not appear until approved by the author. Post another comment

The letters and numbers you entered did not match the image. Please try again.

As a final step before posting your comment, enter the letters and numbers you see in the image below. This prevents automated programs from posting comments.

Having trouble reading this image? View an alternate.

Working...

Post a comment

Comments are moderated, and will not appear until the author has approved them.