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.