Wednesday, July 29, 2009

Real-Time Progress Bar With ASP.NET AJAX

Due to the disconnected nature of the web, developers have often wondered how to display certain metrics such as a real-time progress bar. This article will show you how to easily build a real progress bar that actually reports progress of a process running on the server using ASP.NET AJAX.

Our Scenario

First, let's define our scenario so that we're all on the same page. We'll pretend that we have made a portal (web application) that allows the local IT administrators to run a task on each computer in the office. Since this task takes a variable amount of time, they want to see a real-time progress bar showing how much further the task has to be done.

Now, I don't want to lose you in the scenario, so I'll tell you up front that we are going to completely fake the "run some code on another machine" stuff. Try to keep focus on the fact that we are talking about using ASP.NET AJAX and how to report progress cleanly back to the client.

Our Needs vs ASP.NET AJAX

Let's talk about some of our needs, and how they are solved by ASP.NET AJAX. First of all, like we mentioned before the nature of the web is 'disconnected'. This means that once you write your data to the client (in our case the amount of progress that has passed), the connection is closed, so you can't update values later in the same request).

We will solve this need by implimenting a "polling" architecture by consuming an embeded webservice every second. This may seem like a heavy amount of data being transfered, but it's not. This is because consuming web services in ASP.NET AJAX is a very light weight request as it is not posting or rendering the entire page. As a side note, this is different than when you simply wrap your site in an "UpdatePanel", which *will* upload the entire view state of the page.

The second need we will have is to perform a custom action when the progress is updated. For simplicities sake, we're just going to display the current progress percentage on the page. Instead of messing up each page with a lot of JavaScript, we'll encapsulate the client code into a custom "script control" that has a method we can tap into to perform our desired functionality.

ScriptControls are just regular WebControls. The difference is that they use the ASP.NET AJAX framework to associate JavaScript code with the rendered control. Think about it as if it's a "code-behind" file... that's not "behind", but rather on the client.

Making Our Web Service

Let's start by making the two web service methods that we're going to need for this example. I'm not going to get into too much detail on creating and consuming webservices. If you're not familiar with consuming web services in ASP.NET AJAX, then I suggestion you look at this article: Consuming Web Services With ASP.NET AJAX.

So, as is detailed in that article, I'm going to add my "asmx file" (ASP.NET WebService) to my web application project, and my code behind file will look like this:

using System;
using System.Web.Services;
using System.Web.Script.Services;

namespace SingingEels
{
[ScriptService]
public class DoStuffWebService : WebService
{
[WebMethod, ScriptMethod]
public void BeginProcess(string processName)
{

// Here
is where I'm starting my timers...

}

[WebMethod, ScriptMethod]
public int GetProcessProgress(string processName)
{

// Here
is where I return an integer between 0 and 100

// that tells the progress of the process by name.

}
}
}

The actual code that I'm doing in each of those functions is not important for this article, so I'm intentionally not showing it so that we don't fall off track due to ugly code :P The point to keep in mind here is that, as was mentioned in the article above, web services are easy to create and consume with ASP.NET AJAX.

Polling With AJAX

All that's left now is that we impliment our "ScriptControl" on our page, and wire up a method that tells the browser when to start polling for progress updates, and when to stop (as well as what to do when progress changes). The way I'm going to handle this is by putting most of the code into my ScriptControl. My reasons for doing this are 2 fold:

  1. To segragate the control-specific code into it's own JavaScript file (just like we do with code behind files).
  2. To make it easy to add this progress bar control to another page with only a minimal amount of setup.

I'm going to give my control 2 properties that need to be set. The first property is the "ProcessName" that will be run on the server. I'm simply using this as a "key" so that when I return to the server, I'll be getting the progress of that running process. The second property will indicate the interval (time between polling).

At the end of this article, you can download the entire source code for the project (which is a Visual Studio 2008 Web Application project). But for now, I'll skip ahead and show you how to impliment this control, and what the results will look like:


See full detail: http://www.singingeels.com/Articles/RealTime_Progress_Bar_With_ASPNET_AJAX.aspx