Introduction
When consuming things like long web services or RSS feeds from external web sources, it might be nice to load all of the important parts on the page first and then load the slower loading part(s) later. This example will demonstrate how to load multiple blocks of RSS headlines after the main body of the page has had a chance to load. While the page is loading, placeholders are displayed to indicate that additional content is coming. After the page loads, the content for the placeholders is retrieved and displayed asynchronously.
Oftentimes, there can be a need to load something on a page that may take significantly longer to load than the rest of the page. In some cases, you can use caching to help with this issue, but it may not always be possible or be the only option. If something is going to take longer to load than normal, it is important to display some kind of visual feedback to the user so that they know to wait while something is happening. Retrieving information from a remote server, displaying large sets of data, and photo galleries are just a few examples where delaying the loading of specific content areas would be useful.
Prerequisites
This example uses:
Creating the UserControl
You could do all this on an ASPX page, but for this example, we'll use a UserControl
. I chose to create a UserControl
that consumes an RSS feed called, oddly enough, RSSFeed.ascx. This control uses the ASP:Timer
, ASP:UpdatePanel
and ASP:MultiView
controls to create a block of content that loads 1 millisecond after the page loads.
The UserControl Source (RSSFeed.ascx)
The key areas to look at in the UserControl
's source are:
- The
ASP:Timer
's OnTick
event -- triggered 1ms after the page loads -- triggers the routine to load the RSS headlines from the RSS feed - The
ASP:UpdatePanel
uses AJAX to load the headlines into the content block and changes the ASP:Multiview
without refreshing the page - The
ASP:Multiview
enables multiple display options depending on what stage the content block is in, i.e. default, content loaded, content unable to load
<%@ Control Language="VB" AutoEventWireup="false"
CodeFile="RSSFeed.ascx.vb" Inherits="RSSFeed" %>
<%@ Register Assembly="RssToolkit" Namespace="RssToolkit" TagPrefix="cc1" %>
<%----%>
<cc1:RssDataSource ID="rssData" runat="server"
Url="http://tempuri.com"
MaxItems="5" />
<asp:Panel runat="server" ID="pnlRSS" CssClass="RSSBlock" Width="275">
<asp:Label runat="Server" ID="lblHeader" Text="Headlines" Visible="False" />
<asp:UpdatePanel runat="Server" ID="updateRSS" UpdateMode="Conditional">
<ContentTemplate>
<asp:MultiView runat="server" ID="mvRSS" ActiveViewIndex="0" >
<%----%>
<asp:View runat="Server" ID="view1">
<asp:image runat="server" ID="image1"
ImageAlign="middle" ImageUrl="spinner.gif" />
<asp:Label runat="Server" ID="label1"
Text="Loading..." Font-Size="smaller" ForeColor="orange" />
</asp:View>
<%----%>
<asp:View runat="server" ID="view2">
<asp:Repeater runat="Server" ID="rptRSS">
<HeaderTemplate>
<asp:Label runat="Server" id="lblRSSHeader"
Text='<%# lblHeader.Text %>'
Class="RSSHeader" />
<ul>
</HeaderTemplate>
<ItemTemplate>
<li>
<asp:hyperlink runat="server" ID="linkRSS"
Text='<%# Eval("Title") %>'
NavigateUrl='<%# Eval("Link") %>' />
</li>
</ItemTemplate>
<FooterTemplate></ul></FooterTemplate>
</asp:Repeater>
</asp:View>
<%----%>
<asp:View runat="Server" ID="view3">
<asp:Label runat="Server" ID="lblNoData"
Text="Unable to load headlines at this time."
Font-Size="smaller" ForeColor="orange" />
</asp:View>
</asp:MultiView>
<%----%>
<asp:Timer ID="timerRSS" Interval="1"
OnTick="DisplayRSS" runat="server" />
</ContentTemplate>
</asp:UpdatePanel>
</asp:Panel>
The UserControl CodeBehind (RSSFeed.ascx.vb)
Note the following key areas:
- The two public properties, URL and RSSTitle, will allow you to pass the URL for the RSS feed and the Heading for the content block to the
UserContol
. You'll see how this happens later in the article. - The
DisplayRSS
subroutine is fired through the ASP:Timer
's OnTick event when it's Interval is reached. Of course, you could easily do something else, like display the results of a long-running web service, a large table of data, large images, video, etc.
Option Strict On
Option Explicit On
Imports System.Data
Imports System.Xml
Imports System.Net
Imports System.IO
Partial Class RSSFeed
Inherits System.Web.UI.UserControl
Public WriteOnly Property URL() As String
Set(ByVal value As String)
rssData.Url = value
End Set
End Property
Public WriteOnly Property RSSTitle() As String
Set(ByVal value As String)
lblHeader.Text = value
End Set
End Property
Protected Sub DisplayRSS(ByVal s As Object, ByVal e As EventArgs)
Try
Dim wc As WebClient
wc = New WebClient()
wc.Proxy.Credentials =
System.Net.CredentialCache.DefaultNetworkCredentials
Dim feed As Byte()
feed = wc.DownloadData(rssData.Url)
rptRSS.DataSource = rssData
rptRSS.DataBind()
mvRSS.ActiveViewIndex = 1
Catch ex As Exception
mvRSS.ActiveViewIndex = 2
End Try
timerRSS.Enabled = False
End Sub
End Class
Adding the UserControl to a Webpage
In this example, multiple instances of the RSSFeed UserControl
have been added to Default.aspx to demonstrate the effect. Most of the UserControl
s are given valid RSS URLs, but some have been given invalid or missing URLs to show what happens when the content is not able to load correctly. The RSS feeds are pulled from a variety of different web sources. Here is how you might add the UserControl
to a web page:
At the Top of the Page, After the <%@ Page %> Directive
<%@ Register Src="RSSFeed.ascx" TagName="RSSFeed" TagPrefix="uc1" %>
In the Page Body
Notice that the control is being passed the values for the RSSTitle and URL properties that we created earlier.
<uc1:RSSFeed id="RSSFeed1" runat="server"
RSSTitle="MSDN: United States"
URL="http://msdn.microsoft.com/globalrss/en-us/global-msdn-en-us.xml" />
Running the Example Locally
- Download the example file (VB | C#)
- Extract to a local folder
- Open the DelayedContentLoading folder as a web site in Web Developer Express or Visual Studio 2005
- Build and run the web site
Points of Interest
- When using multiple
UserControl
s with timers in them, they will load serially one after the other. This means that the second UserControl
will start its timer AFTER the first UserControl
loads and so on. - The content in the block is not loaded with the page. Therefore search engines will not index content blocks that are loaded after the page loads. View the source in the online example to see what I mean.
- These content blocks could create accessibility issues. Because they are not added to the page source, I'm not sure how screen readers and other Assistive Technologies (ATs) will react. Perhaps someone could provide some feedback regarding this in the comment section below.
Advanced Options
By creating a UserControl
for the delayed content, we now have a reusable control that we can add dynamically. This being the case, consider the following options for expanding on this idea:
- Load multiple instances of the
UserControl
into an ASP:PlaceHolder
instead of typing them out individually on the page. - If you don't stop the
ASP:Timer
after the OnTick
event fires, it keeps running. If you used a longer interval like 5000 (5 seconds), you could keep the timer running and display a series of content blocks that change every 5 seconds.
History
- 5 June, 2007 -- Original version posted
- 6 June, 2007 -- Updated to work with proxies as suggested by nbr (Noel). Originally suggested on DmitryR's blog
- 24 October, 2007 -- Added C# version of the demo project (thanks Shawn N.!)