ASP.NET uses a pipeline model to process the requests to the scripting engine.
Here is generally how the pipeline model works.
An HTTP request is passed to an instance of the HttpRuntime() class.
The HttpRuntime() object examines the request to find out which application to send the request to.
Then .NET uses a HttpApplicationFactory to either create or find an application.
Once the proper application is found the request is sent to through any HttpModules that are running on that application.
After the modules have operated on the application the application uses a HttpHandlerFactory to either find or create any handler objects.
The final step is to deliver the application.
Take a look at the following figure for a visual representation of the HTTP Processing Pipeline.
What is a HTTP Handler?
So What exactly is a Http Handler? Well, HTTP handlers are the .NET components that implement the
System.Web.IHttpHandler interface. Any class that implements the IHttpHandler interface can handle
incoming HTTP requests.
With Http Handlers you can create your own file extensions, do certain tasks every time a page with
a specific extension is loaded, create progress bars to show status, etc., the list goes on and on.
When you implement any interface you have a certain number of functions that you will need to
implement. The IHttpHandler interface has two functions that you will need to write. They are
the ProcessRequest() function and the IsReuseable() function. The former is the heart of the
Http Handler. The latter strictly tells the ASP.NET worker process whether it can reuse this
Http Handler or not.
How do you create a HTTP Handler?
As I mentioned above you need to implement the ProcessRequest() and IsReuseable() functions in
your own class. So let's create our own class. If you use Visual Studio .NET you can create a
new Web solution by doing the following:
Go to File->New->Project
Go to the Visual C# Projects Folder and choose a ASP.NET Web Application
Give the project a name and click "OK"
Now that you have a new C# Web project created you need to add a class to your project.
I called mine CHttpProgressHandler. Once you have the class up you will need to inherit
from the IHttpHandler interface. Then create a public function called ProcessRequest()
that takes the HttpContext as a parameter and then create a public property called
IsReusable that implements the get property. The code should look something like the following:
using System;
using System.IO;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace MyProgressBar
{
/// <summary>
/// Summary description for CHttpUploadHandler.
/// </summary>
public class CHttpProgressHandler : IHttpHandler
{
public CHttpProgressHandler()
{
//
// TODO: Add constructor logic here
//
}
#region IHttpHandler Members
public void ProcessRequest(HttpContext context)
{
// TODO: Add CHttpProgressHandler.ProcessRequest implementation
}
public bool IsReusable
{
get
{
return true;
}
}
#endregion
}
}
This is the base of all HttpHandlers. Any time that you start creating an Http Handler the class
should look like the above code. Right now this Handler does absolutely nothing. So let's make
it do something. One request that is seen a lot is creating a progress bar to show the user how
long a particular process is going to take. Let's implement our Handler to do exactly that; to
show the user how long a certain process will take.
Before you get to caught up in what the logic of the Handler is let's think about all the elements
you will need to implement this progress indicator. First you will need a way to display a progress
bar on a page. There are a lot of controls out there that you can download if you would like; we
are going to create our own. Then you need a process that takes a certain amount of time to
complete; for this you can implement a loop on a separate page that is triggered by an event.
When that event is triggered you need to pop-up the progress bar. So you will need two pages,
one for to implement a long process, and one to show the progress.
Let's implement our very own Progress Bar Control. To do this you will need to add another
class to your project and inherit from the WebControl class and the INamingContainer interface.
You will have two properties to set, the foreground color and the background color. Then you
need to implement the render function to draw the progress bar. Here is the code for the Progress Bar Control:
Note: This is not a tutorial on how to create controls.
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
namespace Progress
{
/// <summary>
/// Progress bar control is used to display the progress or
/// status of a particular process.
/// </summary>
[DefaultProperty("Text"), ToolboxData("<{0}:ProgressBar runat=server>
</{0}:ProgressBar>")]
public class ProgressBar : WebControl, INamingContainer
{
// Member variables
private int nProgress = 0; // Percentage out of 100
private int nPercentOfProgress = 0; // Percentage in 20ths
/// <summary>
/// Default Constructor
/// </summary>
public ProgressBar()
{
// Set the default colors of the control
this.BackColor = System.Drawing.Color.LightGray;
this.ForeColor = System.Drawing.Color.Blue;
}
/// <summary>
/// Accessor to set the background color of the control
/// </summary>
public override System.Drawing.Color BackColor
{
get
{
return base.BackColor;
}
set
{
base.BackColor = value;
}
}
/// <summary>
/// Accessor to set the foreground color of the control
/// </summary>
public override System.Drawing.Color ForeColor
{
get
{
return base.ForeColor;
}
set
{
base.ForeColor = value;
}
}
/// <summary>
/// Accessor to update the progress of the control
/// </summary>
public int PercentageOfProgress
{
get
{
return nProgress;
}
set
{
// Make sure the progress doesn't have invalid values
if (value > 100)
{
nProgress = 100;
}
else if (value < 0)
{
nProgress = 0;
}
else
{
nProgress = value;
}
// Calculate the percentage done if the progress > 0
if (nProgress != 0)
{
nPercentOfProgress = nProgress / 5;
}
}
}
/// <summary>
/// Renders the progress bar
/// </summary>
/// <param name="output"></param>
protected override void Render(HtmlTextWriter output)
{
// Create a table to render
Table table = new Table();
TableRow row = new TableRow();
table.CellPadding = 0;
table.CellSpacing = 0;
table.BorderWidth = 0;
table.Width = 100;
// Add a row to the table
table.Rows.Add(row);
// Since we split the data into 20ths
// we need a cell for each piece.
// Another option is to use the GDI to
// create a graphic progress bar.
for(int i = 0; i < 20; i++)
{
TableCell td = new TableCell();
td.Width = 5;
td.Height = 16;
// If the count is less then the percent done
// then you need to set it to the fore color.
// Otherwise the progress has not reached this
// cell and you need to set it to the back color.
if (i < nPercentOfProgress)
{
td.BackColor = this.ForeColor;
}
else
{
td.BackColor = this.BackColor;
}
// Add the cell to our row
row.Cells.Add(td);
}
// Add the table to the calling page
this.Controls.Add(table);
table.RenderControl(output);
}
}
}
Now you can create a new Web form and put your control in it.
How to Enable Access to Information in your HTTP Handlers
To make sure the popup-window can reach your information about the progress, you have to save it in the
Application-state. The reason we use the application state to store the information is because Session
state information is not available until the whole process is done. So in order to do this you need to
create a unique key to make sure that every user doesn't get the same progress bar.
You will need to set this value when you are doing your processing. So in your aspx page that is doing
the loading you can put something like this in the code behind page:
private void btnSubmit_Click(object sender, System.EventArgs e)
{
if(Page.IsValid)
{
// Start the proces
for(int i = 0; i <= 100; i++)
{
System.Threading.Thread.Sleep(300);
// Save the progress in the Application-state with
// a unique key for this session
Application["progress_" + Session.SessionID] = i;
}
lblMsg.Text = "<h1>PROCESS FINISHED!!</h1>";
}
This will store the total percentage process in the application state. So in your Http Handler you can
access that Application state variable like this:
#region IHttpHandler Members
public void ProcessRequest(HttpContext context)
{
HtmlTextWriter writer = new HtmlTextWriter(context.Response.Output);
// Build the HTML for the popup
writer.WriteFullBeginTag("html");
writer.WriteFullBeginTag("body");
writer.WriteFullBeginTag("head");
writer.WriteFullBeginTag("title");
writer.Write("Progress");
writer.WriteEndTag("title");
writer.WriteBeginTag("meta");
writer.WriteAttribute("http-equiv","refresh");
writer.WriteAttribute("content","1");
writer.Write(HtmlTextWriter.TagRightChar);
writer.WriteEndTag("head");
writer.WriteFullBeginTag("body");
int progress;
// When the process is unknown in the Application-state, the process is 0
if(context.Application["progress_" + context.Request.Params["id"]] == null)
progress = 0;
// Else this equals the int in the Application-state
else
progress = (int) context.Application["progress_" +
context.Request.Params["id"]];
// Create the progressbar
Progress.ProgressBar pbProgress = new Progress.ProgressBar();
pbProgress.ID = "ProgressBar";
// Set the value of the progressbar
pbProgress.PercentageOfProgress = progress;
pbProgress.RenderControl(writer);
writer.Write("<div align=\"center\">" + progress + "%</div>");
// If the proces is finished,
if(progress == 100)
{
// Close the popup-window using JavaScript
writer.WriteBeginTag("script");
writer.WriteAttribute("language","javascript");
writer.Write(HtmlTextWriter.TagRightChar);
writer.Write("window.close();");
writer.WriteEndTag("script");
// DON'T FORGET to remove the variable from the Application-state,
// otherwise it will exist 'forever'
context.Application.Remove("progress_" + context.Request.Params["id"]);
}
writer.WriteEndTag("body");
writer.WriteEndTag("html");
}
Registering Your HTTP Handlers with .NET
Registering HTTP Handlers with your .NET Web Application is extremely simple. All you have to do
is add a new section to your <system.web> portion of your Web.Config file. The new section
should look something like this:
This article includes the source files which you can download from here: ProgressBar.zip (21 KB).
The Page that does the processing, in other words the page that
you want to display the progress bar for, is called UploadForm.aspx. This page triggers a popup that
loads ProgressBar.aspx. The HttpHandler that we specified in the Web.Config file catches any requests
to ProgressBar.aspx and pipes them through the CHttpUploadHandler class. The process request in the
class file prints a progress bar to the ProgressBar.aspx document.
Conclusion
I hope you enjoyed this article and you will find it usefull. If you have any questions please feel
free to e-mail me at ruts@datausa.com. Happy Coding!