FireBug graph of net requests
When rolled into the page life cycle of an ASP.NET WebForm, that red bar is one of your application’s greatest enemies. No matter how well you optimize the rest of the page, even one slow task can become the sole factor determining a user’s perception of the entire page’s performance.

In this post, I’m going to show you one way to circumvent that problem. By placing ancillary content in user controls and delaying their load until the core page content has been displayed, you can drastically improve perceived performance.

When broken down into digestible chunks, the technique is easy to implement and lends your application a level of polish that your users are sure to appreciate. The four steps required to accomplish this will be: building the user control, statelessly rendering the control as HTML, providing progress indication, and using ASP.NET AJAX to request and inject that HTML.


Building the user control

First, we need some slow-loading, auxiliary content to encapsulate in a user control. For this example, that’s going to be a minimal RSS feed reader widget that displays the most recent posts from this site.

The key activity here is retrieving my RSS feed and querying it for some basic information. To expedite this, I’m going to use one of ASP.NET 3.5’s great new features: LINQ to XML. LINQ really makes short work of this normally tedious task. It still blows me away every time I use it.

protected void Page_Load(object sender, EventArgs e)
{
  XDocument feedXML = 
    XDocument.Load("http://feeds.encosia.com/Encosia");
 
  var feeds = from feed in feedXML.Descendants("item")
              select new
              {
                Title = feed.Element("title").Value,
                Link = feed.Element("link").Value,
                Description = feed.Element("description").Value
              };
 
  PostList.DataSource = feeds;
  PostList.DataBind();
}

To display this, I’m going to use another of ASP.NET 3.5’s new features, the ListView control:

<asp:ListView runat="server" ID="PostList">
  <LayoutTemplate>
    <ul>
      <asp:PlaceHolder runat="server" ID="itemPlaceholder" />
    </ul>
  </LayoutTemplate>
  <ItemTemplate>
    <li><a href='<%# Eval("Link") %>'><%# Eval("Title") %></a><br />
      <%# Eval("Description") %>          
    </li>
  </ItemTemplate>
</asp:ListView>

Example of the RSS feed widget controlWith a little bit of CSS (included in the source download later), this results in something resembling the screenshot to the right.

The ListView comes in especially handy for our purposes here, because it gives you such effortless control over the rendered HTML. When injecting generated HTML into a page, you really appreciate knowing exactly what markup to expect.

Rendering the user control as HTML

The next step is to create a web service that statelessly renders our user control as an HTML string. By statelessly, I mean that we need to render this user control outside the context of an active ASP.NET Page instance, where user controls are normally intended to be used.

To solve that problem, you can create a temporary instance of the ASP.NET Page class, dynamically add the user control to it, and then execute it within the web service’s context. Doing this turns out to be easier than it is to accurately describe:

[WebMethod]
public string GetRSSReader()
{
  // Create a new Page and add the control to it.
  Page page = new Page();
  UserControl ctl = 
    (UserControl)page.LoadControl("~/RSSReaderControl.ascx");
  page.Controls.Add(ctl);
 
  // Render the page and capture the resulting HTML.
  StringWriter writer = new StringWriter();
  HttpContext.Current.Server.Execute(page, writer, false);
 
  // Return that HTML, as a string.
  return writer.ToString();
}

You might worry about creating an entire Page instance for what is supposed to be a performance enhancing technique. At first, I shared the same concern.

However, since our Page instance is created outside of the normal ASP.NET HTTP pipeline and only contains one control, the overhead is negligible. The Page itself is fairly performant compared to all of the other work involved in a typical HTTP round-trip.

Setting up the demonstration page

To demonstrate, we’ll need a page with some fast-loading content to provide contrast. Inside that, we can embed an empty DIV which will be used to accurately inject the user control’s rendered HTML.

<asp:ScriptManager runat="server">
  <Services>
    <asp:ServiceReference Path="~/RSSReader.asmx" />
  </Services>
  <Scripts>
    <asp:ScriptReference Path="~/Default.js" />
  </Scripts>
</asp:ScriptManager>
<div id="Container">
  <div id="RSSBlock" class="loading"></div>
  <div id="Content">
    <p>Lorem ipsum dolor sit amet, consectetuer adipiscing...</p>
  </div>
</div>

As you can see, the RSSBlock DIV is initially assigned a CSS class of “loading”. This is the CSS for the loading class:

.loading { 
  background: url('progress-indicator.gif') no-repeat center; 
}

Progress indicator displayed while the user control loadsWhat this does is give us a bit of rudimentary progress indication. Until we update it later, it will display an empty placeholder with an indicator.

You and I know that it’s a bit of a scam, but your users will never realize the progress indicator isn’t real. I won’t tell if you won’t!

Calling the web service from JavaScript

Now that we’ve got a place to inject it, the final step is to retrieve the HTML rendering of our user control and insert it into the page. ASP.NET AJAX takes all of the hard work out of this step:

Sys.Application.add_init(AppInit);
 
function AppInit() {
  RSSReader.GetRSSReader(OnSuccess, OnFailure);
}
 
function OnSuccess(result) {
  // Remove the .loading CSS from the div, to remove the 
  //  progress indicator background.
  Sys.UI.DomElement.removeCssClass($get('RSSBlock'), 'loading');
 
  // Fill the div with the HTML generated from the user control.
  $get('RSSBlock').innerHTML = result;
}
 
function OnFailure() {
  // Do something if our callback fails.  Retry it, perhaps.
}

Since it’s only a CSS class, disabling the progress indication is as simple as using removeCssClass to remove it from the DIV. For more on removeCssClass, check out my recent article about ASP.NET AJAX’s client side UI methods.

With the animated background removed, we are now free to insert the rendered HTML into the DIV’s innerHTML. The end result is exactly the same as if we had placed the user control inside that DIV, without unnecessarily delaying the entire page load.

Conclusion

I think you’ll find that this technique is very powerful. It allows you to leverage your existing knowledge of ASP.NET and its server controls as a robust templating solution for lightweight AJAX. At the same time, it exudes the kind of professional usability that typically requires more tedious and less maintainable client side coding.

Note that there is not an UpdatePanel anywhere on this page. Using this technique does not require relying on partial postbacks. Not only does that improve performance, but also allows UpdatePanels elsewhere on the page to operate normally, while the deferred content loads.

Download source: uc-delay-load.zip (36kb)

Check out the full demonstration by downloading the source and running it yourself. You really have to see it in action to truly appreciate it. The download also includes at least one improvement that I didn’t have room to write about in this post. Give it a try and let me know what you think.