Monday, October 15, 2007

So, last week at work I tackled what is probably the infamous content management issue with ASP.NET AJAX. I've found a good thread on this at online but I wanted to write about my investigation and solutions (gathered from a few sites and also from tracing through our content management system) for the benefit of... someone, I hope. :)

Stating the problem is easy: AJAX doesn't work with our home grown content management system. The CMS predates me by a few years, so this was my first time digging into its guts.

Before digging into the meat of the problem, let me share my troubleshooting configuration. It's important to have the right tools and the right approach to simplify your life, and in this case I used Fiddler as my main tool to trace HTTP requests. Next, I created a simple ASP.NET AJAX application - an UpdatePanel that displays the current time (calculated server side) and has a button to perform the asynchronous post back. Executing this while Fiddler is running gave me a clean example of a request/response on page load and on an asynchronous post back. In some ways this is like a "control" in a science experiment, but the comparison only goes so far (we're engineering here, not science-ing, even if we share some thought processes)  Having an HTTP tracer and a clean point of comparison made it a lot easier to track down the AJAX problems in our content management system (CMS).

The CMS is an IIS web application, and can serve both static content and dynamic content (ASPX pages) from other websites. It uses a template system to put content together, but the details of this aren't important to explain the issue and solution.

Let's say the main site (the content management system) is under /CMS and a sample content site is at /ContentSite

The CMS application has an ASPX page named "serveContent" that is passed an identifier which it then resolves to actual content. The requested page can contain other pages, so CMS aggregates them and sends them to the client. This is, more or less, the expected configuration of a content management system.

The issue with AJAX happens when an ASPX page (with AJAX content) is aggregated and sent to the client. The requesting page, from the client, might look like http://localhost/CMS/serveContent.aspx?id=123 but ASPX pages will have the "action" property of their "form" element set to something like http://localhost/ContentSite/someAspxPage.aspx. Even though I'm an experienced developer and can derive solutions on my own, it's still quite wise to research online. Software can be complex and a solution that sounds good requires a sanity check to make sure you aren't making a faulty assumption or not taking something important into account, not to mention, finding solutions fast before writing new code and debugging it. (BTW, if someone reads this and realizes I'm doing something stupid here, please let me know!)

At this point, I figured the solution was to modify the form's action on the response's way out, and this page concurred Fixing Microsoft's Bugs: Url Rewriting. The most important part of his code is the WriteAttribite method of FormFixerHtmlTextWriter. After applying this code, and tweaking a number of things specific to our content management system, AJAX finally worked.

But only on the first asynchronous post back.

The next problem was with how UpdatePanel works. I am unsure if this is a bug with ASP.NET AJAX or there are design reasons but when an asynchronous post back occurs with UpdatePanel, the "action" property on the "form" is forced back to its original form. Now I need to change the action again! This fix was accomplished by changing the response stream. I found the solution over at this page http://forums.asp.net/p/1037846/1809800.aspx, 10 posts down. I'm unsure if this is the best solution, but I prefer it to a client side solution (changing the form action using JavaScript) because it's not dependent on the client to ensure the pages work. I didn't explore it too deeply, but apparently the following code on the client will solve this problem. Note it's important to set the initial action AND the action properties.

Sys.Application.add_load(function() {

   var form = Sys.WebForms.PageRequestManager.getInstance()._form;

   form._initialAction = form.action = window.location.href;

});

I found this snippet of code at here in the ASP.NET forums. Scroll to the bottom, to Jeffrey Zhao's post.

I wanted as little extra code as possible to fix this issue and I'm fairly happy with where things are. It was nice to see HTTP 200's in Fiddler with each asynchronous post back, after taking a fair chunk of time to track this down.

Thanks to Jesse Ezell, fitsner and Jeffrey Zhao for posting useful code online.

Monday, October 15, 2007 10:52:36 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0]  |  Trackback
Comments are closed.