Click here to Skip to main content
13,899,680 members
Click here to Skip to main content
Add your own
alternative version


49 bookmarked
Posted 30 Oct 2007
Licenced CPOL

Incremental Page Display Pattern for User Controls

, 30 Oct 2007
Rate this:
Please Sign up or sign in to vote.
A solution for loading user controls asynchronously via AJAX with no custom JavaScript required.


Screenshot - loading.gif



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.


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:

public class IncrementalLoader : System.Web.UI.WebControls.CompositeControl, IScriptControl
    protected override void OnInit(EventArgs e)
        // JavaScript registration - only happens for the first server control loaded

        if (!this.Page.ClientScript.IsClientScriptIncludeRegistered(
            string resource = this.Page.ClientScript.GetWebResourceUrl(this.GetType(), 
                "__IncrementalLoaderScript", resource);
    // Gets a path for the javascript to query.  This points to the HTTP handler

    public string GetCallbackPath()
        string path = this.Page.Request.Path;

        if (!string.IsNullOrEmpty(path))
            path = path.Replace(".aspx", HandlerExtension);

        string controlLocation = this.Page.ResolveUrl(this.ResourceToLoad);
        string query = Utility.EncryptString(controlLocation);

        path += "?" + ControlQuery + "=" + HttpUtility.UrlEncode(query);

        return path;
    // Each server control instance renders a single line of JavaScript to load 

    // the user control when the browser is done loading the page.

    public string RenderLoadScript()
        return "LoadContent('" + GetCallbackPath() + "', '" + 
               _contentPanel.ClientID + "', '" 
               + _loadingPanel.ClientID + "', '" + 
               _faultPanel.ClientID + "');";
    // Registers the startup script 

    private void RetisterClientScript()
        StringBuilder script = 
          new StringBuilder("<script type="\"text/javascript\""></script>\r\n");

        this.Page.ClientScript.RegisterStartupScript(this.GetType(), _
                               contentPanel.ClientID + 
                               "LoadingScript", script.ToString());

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.

public void ProcessRequest(HttpContext context)
    // *** Simulate latency ***

    Random r = new Random();
    int wait = r.Next(500, 3000);

    if (context.Request.QueryString[IncrementalLoader.ControlQuery] != null)
            // Create a page instance to host the user control

            Page page = new Page();

            string controlLocation = 
            UserControl control = (UserControl)page.LoadControl(controlLocation);


            // Execute the page and return the output
            // (only the control's output is returned)

            StringWriter output = new StringWriter();
            context.Server.Execute(page, output, false);

        catch { }

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!



This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Web Developer PageLabs
United States United States
I'm the founder of PageLabs, a web-based performance and SEO optimization site.

Give your site a boost in performance, even take a free speed test!

You may also be interested in...


Comments and Discussions

Generaldynamically adding IncrementalLoader..... Pin
vidhyasagar20-Aug-08 20:51
membervidhyasagar20-Aug-08 20:51 
GeneralFF not functioning Pin
Ervin Ter5-Nov-07 17:04
memberErvin Ter5-Nov-07 17:04 
GeneralRe: FF not functioning Pin
warrenvdm7-Nov-07 13:11
memberwarrenvdm7-Nov-07 13:11 
GeneralRe: FF not functioning Pin
TylerBrinks10-Nov-07 9:26
memberTylerBrinks10-Nov-07 9:26 
GeneralRe: FF not functioning Pin
Hopeto Chophi5-Jan-11 22:00
memberHopeto Chophi5-Jan-11 22:00 
GeneralInteresting... what's next it's even more interesting Pin
giurgiu5-Nov-07 8:21
membergiurgiu5-Nov-07 8:21 
GeneralRe: Interesting... what's next it's even more interesting Pin
TylerBrinks5-Nov-07 9:20
memberTylerBrinks5-Nov-07 9:20 
GeneralRe: Interesting... what's next it's even more interesting Pin
giurgiu5-Nov-07 9:30
membergiurgiu5-Nov-07 9:30 
GeneralVery good, however a note Pin
paragme30-Oct-07 18:22
memberparagme30-Oct-07 18:22 

Article is great, but just for the clarity, pls mention that this technique only works for "read-only" controls. In other words, you can can't have a datagrid or other controls which uses Postbacks.

Best Regards,
Parag Mehta


GeneralRe: Very good, however a note Pin
TylerBrinks31-Oct-07 3:19
memberTylerBrinks31-Oct-07 3:19 
GeneralRe: Very good, however a note Pin
Allen Berezovsky11-Dec-07 14:46
memberAllen Berezovsky11-Dec-07 14:46 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web02 | 2.8.190306.1 | Last Updated 30 Oct 2007
Article Copyright 2007 by TylerBrinks
Everything else Copyright © CodeProject, 1999-2019
Layout: fixed | fluid