Loading...

Contents

Introduction

I'll be the first to admit that, even as a developer, I "ooh" and "ahh" over web sites with really clean and usable AJAX implementations. I'm often frustrated that most of the cool AJAX-esque libraries aren't targeted at ASP.NET. In particular, I've come across several sites recently that use an incremental page display pattern to display content after the page is loaded. I know that ASP.NET AJAX and the Control Toolkit have support for calling web services to display HTML output, but I dislike this approach for quite a few reasons (too many for this article). Plus, calling web services doesn't give developers a way to render user controls and other truly dynamic content. That's far too limiting to be very useful.

Purpose

My goal in this article is to lay the groundwork for loading content, specifically user controls (.ascx controls), on the fly. To give credit where it's due, some of the inspiration for this article comes from Scott Guthrie's UI templating article. I like Scott's approach to avoiding the UpdatePanel as well as using templated user controls. His idea is a good starting point, but I'm interested in having a server control I can drag onto a page and be done. I'm especially interested in one that lets me write zero JavaScript. Like most developers, I'd prefer to spend my time writing code, not hard-to-maintain client scripts.

A Working Example

The Server Control

Let's dive right into the example code. The code is primarily made up of two parts; a server control, and an HTTP request handler. Let's start with the server control. The purpose of the server control is simply to generate a client-side callable JavaScript used to call the server for the contents of a user control. All the server control needs in order to render the script is the relative path of the user control that will be rendered. Here's how the code works:

There's not much to it. The server control just writes out a little bit of JavaScript. The server control also provides templates to define the mark up to be shown while the control is loading, and if an error is encountered. Note that the query string built by the server control is encrypted. You wouldn't want prying eyes seeing the relative paths to your user controls.

The Handler

Let's move on to the HTTP Handler. The hander is responsible for rendering the output for the specified user control. The handler takes incoming HTTP requests (for .ashx extensions in this example) and parses the encrypted query string to determine which user control to load. The user control is loaded by creating an empty Page object, adding the user control to the Page's control collection, and executing the Page. The resulting HTML is sent back to the browser to be rendered. For example purposes, the handler simulates latency up to 3 seconds.

All seems simple, right? It is a clean and easy way to get the output HTML needed to populate the UI, and it takes next to no code.

Still, there are already some fundamental flaws with this code.

Pros and Cons

On the up side, pages load extremely fast since there's only minimal data to load on post back. I'm of the opinion that when the user can see even a little content, it's a better experience than waiting for a whole page to load. Also, based on my initial metrics, loading dynamic content takes as much time (overall duration of loading all controls) as a standard page load.

Also, if your page contains a long-running user control, other parts of the page are usable while the long-running content is being processed.

There are, of course, down sides to the approach. The most obvious problem is that each dynamic user control costs one additional round trip to the server. While the traffic is minimal and asynchronous, there's still a higher overall volume for the server to deal with. Obviously, this is a serious consideration to take into account before employing this pattern.

The most frustrating down side right now is the inability to use ASP.NET controls that require a form tag. Hyper links, for example, don't need to be contained inside a form tag since they don't necessarily post back to the current page. A button, however, requires a form tag to operate. Until someone comes up with a way to manage state and event registration, this solution has a limitation as to which controls can be used.

Note: the sample download does contain one possible work around for the form tag issue. I got all the controls to render, but the view state and events are lost.

A Call for Help

I simply have not had time to dig into the ASP.NET pipeline and page architecture to tackle how view state and events can be maintained outside of having a page to post back to. I'm officially asking, for anyone interested, to help complete the project by finding a way to maintain state and events for the dynamically loaded controls! Any help or ideas are welcome!

I noticed this behaviour as well I managed to put some break points in the Javascript and found that an error was being raised on the "if(document.all)" line in the IncrementalLoader.js file as per below snippet

within the OnContentRetreived function. If you comment out the if(document.all) line as I have done, then it seems to work in firefox. I found that it doesnt appear that document.all is a valid object in firefox, I assume that it just doesnt raise an error in IE thats why it works in IE....

I really appreciate your article but I am more interested in the second part which is missing at the moment.
One question, what happens if the loaded user control has some JavaScript attached?
In the meantime take a look at http://ajaxwidgets.com/ They solved the problem with view state and dynamically loading JavaScript files.
I am looking forward to seeing interesting continuation of this article.

I'll take a look at the Gaia widgets for sure. Have you had success with them before? I'm very interested in how to solve viewstate challenges in particular.

As for a final solution - the best idea I've heard so far is to change the names of the hidden fields that hold state information when you call the .Execute method. Then, assuming postbacks and callbacks go through the same handler, the state can be re-hydrated in the calling user controls. That'd be a ton of work, but it sounds like it's possible.

"The most frustrating down side right now is the inability to use ASP.NET controls that require a form tag. Hyper links, for example, don't need to be contained inside a form tag since they don't necessarily post back to the current page. A button, however, requires a form tag to operate. Until someone comes up with a way to manage state and event registration, this solution has a limitation as to which controls can be used.

Note: the sample download does contain one possible work around for the form tag issue. I got all controls do render, but view state and events are lost."