Build a Dynamic Progress Page
For ASP.NET Pages
By Peter A. Bromberg, Ph.D.

Peter Bromberg

"Humanity is acquiring all the right technology for all the wrong reasons." -- R. Buckminster Fuller

We get a lot of forum posts here on eggheadcafe.com asking how to create various types of progress indicators for ASP.NET pages that take a long time to load (for whatever reason). In classic ASP this is relatively easy since the script is interpreted and you can fiddle with the Response buffer to generate "chunks" of content that are spewed out as the server processes the page. However, in ASP.NET, the entire Page class is compiled (a good thing) and so these little tricks won't work. Since this is a popular topic, I thought I would try to make at least one contribution that can help people get off on the right track to this issue.

 



There are probably half a dozen or more ways to accomplish this task, including using a hidden IFRAME with Remote Scripting, using the XMLHTTP COM object from the client side (a technique that is actually used in ASP.NET 2.0 with partial page caching and callbacks), using popup windows, and other little tricks. The one I present here is one of the simplest. It uses an intermediate page with some timed script on the client side that has actually loaded the destination page with the long running process in the background. All you do is have a button or hyperlink in the page that wants to call the long - running page which really loads the intermediate script page, and has the real destination page on the querystring, like so:

<A HREF="ProgressPage.aspx?destPage=EndPage.aspx">Kick off long running process</a>

The "ProgressPage.aspx" has client script that looks like this:

<title>Loading, please wait...</title>  
  <script> 
  var ctr = 1;
  var ctrMax = 50; // how many is up to you-how long does your end page take?
  var intervalId;  
  function Begin() 
  {
    //set this page's window.location.href to the target page
   window.location.href = "<%= Request.QueryString["destPage"]%>";
   // but make it wait while we do our progress...
   intervalId = window.setInterval("ctr=UpdateIndicator(ctr, ctrMax)", 500);
  } 
  function End() {
  // once the interval is cleared, we yield to the result page (which has been running)
   window.clearInterval(intervalId);   
  }
 
  function UpdateIndicator(curCtr, ctrMaxIterations) 
  {  
   curCtr += 1;   
   if (curCtr <= ctrMaxIterations) {
    indicator.style.width =curCtr*10 +"px";
    return curCtr;
   }
   else 
   {
    indicator.style.width =0;
    return 1;
   }
  }
  </script>
</HEAD>
 <body onload="Begin()" onunload="End()">
  <form id="Form1" method="post" runat="server">
      <div align="center"><h3>Loading Data, please wait...</h3></div>
   <table id=indicator border="0" cellpadding="0" cellspacing="0" width="0" height="20" align="center" >
    <tr>
     <td  align="center"  bgcolor=red width="100%"></td>
    </tr>
   </table>
  </form>
 </body>

What the above script does is as follows:

  • In Body onload, Begin() is called. This immediately sets the location.href property of the window to the final page, which begins loading immediately in the background while the rest of the script runs.
  • We set the intervalId variable to the call to window.setInterval("ctr=UpdateIndicator(ctr, ctrMax)", 500); which sets a timed call to the UpdateIndicator method every 500 milliseconds.
  • UpdateIndicator increments the ctr variable and increase the DHTML width of table "indicator' to the value of ctr * 10 pixels. This is client side DHTML code so it executes in the browser immediately.
  • When the target page has completed loading, the onUnload event is called and the interval timer is cleared in the End() method Your end page will then take over and you will see the result.

In my Endpage.aspx, the page with the long running process, I've put in a routine that actually does some real work that takes time (instead of Thread.Sleep(xxx) which most examples would show):

private void Page_Load(object sender, System.EventArgs e)
  { 
      //Kick off your long running process here...
      // this is just a surrogate for whatever long running 
   //process your page does.
    Response.Write("<ul>");
   WebClient wc= new WebClient();     
   for(int i= 1; i<40;i++)
   {    
   byte[] b=wc.DownloadData("http://www.microsoft.com");
  Response.Write("<li>Got Microsoft " + i.ToString()+" Length: "  + b.Length.ToString());  
   }
   Response.Write("</ul>");
  }

The above code uses the WebClient class to request the Microsoft home page 40 times, and each time the result comes back, it adds a line with some info to an unordered list.

The result of all this is that when the user clicks the link to go to the long-running page, they will first see our Progress page with a red indicator that steadily increases in width until the target page has completed processing:

You can download the sample solution below. It should be easy to adapt this to your specific needs.

Download the Visual Studio.NET Solution that accompanies this article

 



Peter Bromberg is a C# MVP, MCP, and .NET consultant who has worked in the banking and financial industry for 20 years. He has architected and developed web - based corporate distributed application solutions since 1995, and focuses exclusively on the .NET Platform.
Article Discussion: