This example shows how to show a Pure HTML Progress Bar during an upload. It assumes that minimal configuration settings in the web.config file are implemented.

 

   
ASP
 
progressupload.aspx    
     

Our multipart HTML form contains one file field for upload and one text field.

The form action takes a URL which contains a Unique ID used to identify the transfer. It is this ID which allows the progress bar to connect with the uploading page.

When the form is submitted we will need to submit both the data in the main window and also spawn off a separate window to track progress. So instead of using a standard submit button we use a normal button with a client side JavaScript attached to it.

When the submit button is clicked the DoUpload client side function takes over. Before it allows the form to be submitted it takes the Unique ID - used to identify the transfer - and spawns a progress window (progressbar.aspx) putting the ID into the URL so that it can be picked up later.

This is an unusual use of HTTP and worth reiterating. The progressbar.aspx page has an ID supplied to it via the URL (i.e. a GET request). The progressupload.aspx page has the content of the form submitted to it via a standard POST and also has an ID supplied via the URL.

[C#]
<%@ Import Namespace="WebSupergoo.ABCUpload6" %>
<HTML>
<body>

  <script language="javascript">
  <!--
  function DoUpload(inUniqueID) {
    theFeats = "height=160,width=600,location=no,menubar=no,resizable=no,scrollbars=no,status=no,toolbar=no";
    window.open("progressbar.aspx?ProgressID=" + inUniqueID, inUniqueID, theFeats);
    document.myform.submit();
  }
  //-->
  </script>

  <% int theID = Progress.UniqueID(); %>
  <form name="myform" method="post" enctype="multipart/form-data" action="progressupload.aspx?UploadID=<% = theID %>">
  <input type="file" name="filefield1"><br><br>
  <input type="text" name="textfield1" value="some text"><br><br>
  <input type="button" name="dosubmit" value="Upload" OnClick="DoUpload(<% = theID %>)"><br>
  </form>

[VB]
<%@ Import Namespace="WebSupergoo.ABCUpload6" %>
<HTML>
<body>

  <script language="javascript">
  <!--
  function DoUpload(inUniqueID) {
    theFeats = "height=160,width=600,location=no,menubar=no,resizable=no,scrollbars=no,status=no,toolbar=no";
    window.open("progressbar.aspx?ProgressID=" + inUniqueID, inUniqueID, theFeats);
    document.myform.submit();
  }
  //-->
  </script>

  <% Dim theID As Integer = Progress.UniqueID() %>
  <form name="myform" method="post" enctype="multipart/form-data" action="progressupload.aspx?UploadID=<% = theID %>">
  <input type="file" name="filefield1"><br><br>
  <input type="text" name="textfield1" value="some text"><br><br>
  <input type="button" name="dosubmit" value="Upload" OnClick="DoUpload(<% = theID %>)"><br>
  </form>

For the upload processing section we'll make use of some advanced ABCUpload features designed for the efficient processing of very large uploads.

We start by creating an Upload object and check that we've received an uploaded file. If there's no file the most likely cause is that the client is requesting the form rather than uploading a file.

If we have a file we check to see if the file data has been cached as a temporary file. This type of caching will only occur if the GigUpload functionality is enabled.

If the file has been cached and it's not in an encoded format we detach it from the upload and move it wherever we want it to go. This avoids having two copies of a file on disk and it is also much faster if you are dealing with very large files.

If the file hasn't been cached or it's in an encoded format we use the SaveAs method to save the file to disk. This will be less efficient than a move operation if the uploaded data is many hundreds of MB in size.

Finally we report the file name using the properties associated with the Upload object and we report the contents of our text field using the standard ASP.NET Form collection.

[C#]
<%

Upload theUpload = new Upload();
UploadedFile theFile = theUpload.Files["filefield1"];
if ((theFile != null) && (theFile.ContentLength > 0)) {
  if ((theFile.TempFile == "") || (theFile.MacBinary == true)) // save using URL
    theFile.SaveAs("write/" + theFile.WinSafeFileName);
  else { // faster to move than copy
    string thePath = Server.MapPath("write/") + theFile.WinSafeFileName;
    if (System.IO.File.Exists(thePath))
      System.IO.File.Delete(thePath);
    System.IO.File.Move(theFile.Detach(), thePath);
  }

  // Say what was in the form.
  // Note the simultaneous use of both the ABCUpload upload
  // objects and of the built-in ASP.NET Request.Form collection.
  Response.Write("<H1>Upload Complete...</H1>");
  if (theFile != null)
    Response.Write("<P>File Name: " + theFile.WinSafeFileName + "</P>");
  Response.Write("<P>Field Content: " + Request.Form["textfield1"] + "</P>");
}

%>
</body>
</HTML>

[VB]
<%

Dim theUpload As Upload = New Upload()
Dim theFile As UploadedFile = theUpload.Files("filefield1")
Dim theLength As Long = 0
If (Not theFile Is Nothing) Then theLength = theFile.ContentLength
If (theLength > 0) Then
  If (theFile.TempFile = "") Or (theFile.MacBinary = True) Then ' save using URL
    theFile.SaveAs("write/" + theFile.WinSafeFileName)
  Else ' faster to move than copy
    Dim thePath As String = Server.MapPath("write/") + theFile.WinSafeFileName
    If System.IO.File.Exists(thePath) Then
      System.IO.File.Delete(thePath)
    End If
    System.IO.File.Move(theFile.Detach(), thePath)
  End If

  ' Say what was in the form.
  ' Note the simultaneous use of both the ABCUpload upload
  ' objects and of the built-in ASP.NET Request.Form collection.
  Response.Write("<H1>Upload Complete...</H1>")
  If (Not theFile Is Nothing) Then
    Response.Write("<P>File Name: " + theFile.WinSafeFileName + "</P>")
  End If
  Response.Write("<P>Field Content: " + Request.Form("textfield1") + "</P>")
End If

%>
</body>
</HTML>

 

   
ASP
 
progressbar.aspx    
     

The progress bar is slightly more complicated. We insert meta-tags to ensure that it refreshes itself every couple of seconds. We create a Progress object and set the ID to the Unique ID we were passed in the URL. This synchronizes the Progress object with the matching upload.

We want to close the progress window once the transfer has been completed so we put in a simple piece of client side JavaScript to do this. The rest of the form simply reports to the user the information retrieved via the Progress object. The progress bar itself is simply a table containing a colored cell of a particular width.

[C#]
<%@ Import Namespace="WebSupergoo.ABCUpload6" %>

<%

Progress theProgress = new Progress(Request.QueryString["ProgressID"]);
string theID = theProgress.ID.ToString();
string theMins = ((int)theProgress.SecondsLeft / 60).ToString();
string theSecs = ((int)theProgress.SecondsLeft % 60).ToString();
string theMeta = "<meta http-equiv=\"refresh\" content=\"2,progressbar.aspx?ProgressID=" + theID + "\">";
string thePercent = theProgress.PercentDone.ToString();
string theKbps = Math.Round(theProgress.BytesPerSecondCurrent / 1024, 1).ToString();
string theKbdone = Math.Round((double)theProgress.BytesDone / 1024, 1).ToString();
string theKbtotal = Math.Round((double)theProgress.BytesTotal / 1024, 1).ToString();
string theNote = theProgress.Note;
string theFileName = theProgress.FileName;
if (theProgress.Finished) theMeta = "";

%>
<HTML>
<HEAD>
<title>Progress...</title>
<meta http-equiv="expires" content="Tue, 01 Jan 1981 01:00:00 GMT">
<% = theMeta %>
<script language="javascript">
<!--
if (<% = thePercent %> >= 100) top.close();
//-->
</script>
</HEAD>
<body bgcolor="#cccccc">
<table border="0" width="100%">
<tr>
<td><font face="Verdana, Arial, Helvetica, sans-serif" size="2"><b>Uploading:</b></font></td>
</tr>
<tr bgcolor="#999999">
<td>
<table border="0" width="<% = thePercent %>%" cellspacing="1" bgcolor="#0033ff">
<tr>
<td><font size="1">&nbsp;</font></td>
</tr>
</table>
</td>
</tr>
<tr>
<td>
<table border="0" width="100%">
<tr>
<td><font face="Verdana, Arial, Helvetica, sans-serif" size="1">Estimated time left:</font></td>
<td><font face="Verdana, Arial, Helvetica, sans-serif" size="1">
<% = theMins %> min
<% = theSecs %> secs
(<% = theKbdone %> KB of
<% = theKbtotal %> KB uploaded)
</font></td>
</tr>
<tr>
<td><font face="Verdana, Arial, Helvetica, sans-serif" size="1"> Transfer Rate:</font></td>
<td><font face="Verdana, Arial, Helvetica, sans-serif" size="1"><% = theKbps %> KB/sec</font></td>
</tr>
<tr>
<td><font face="Verdana, Arial, Helvetica, sans-serif" size="1">Information:</font></td>
<td><font face="Verdana, Arial, Helvetica, sans-serif" size="1"><% = theNote %></font></td>
</tr>
<tr>
<td><font face="Verdana, Arial, Helvetica, sans-serif" size="1">Uploading File:</font></td>
<td><font face="Verdana, Arial, Helvetica, sans-serif" size="1"><% = theFileName %></font></td>
</tr>
</table>
</td>
</tr>
<tr>
</tr>
</table>
</body>
</HTML>

[VB]
<%@ Import Namespace="WebSupergoo.ABCUpload6" %>

<%

Dim theProgress As Progress = New Progress(Request.QueryString("ProgressID"))
Dim theID As String = theProgress.ID.ToString()
Dim theMins As String = CInt(theProgress.SecondsLeft / 60).ToString()
Dim theSecs As String = CInt(theProgress.SecondsLeft Mod 60).ToString()
Dim theMeta As String = "<meta http-equiv=""refresh"" content=""2,progressbar.aspx?ProgressID=" + theID + """>"
Dim thePercent As String = theProgress.PercentDone.ToString()
Dim theKbps As String = Math.Round(theProgress.BytesPerSecondCurrent / 1024,1).ToString()
Dim theKbdone As String = Math.Round(CType(theProgress.BytesDone / 1024, Double), 1).ToString()
Dim theKbtotal As String = Math.Round(CType(theProgress.BytesTotal / 1024, Double), 1).ToString()
Dim theNote As String = theProgress.Note
Dim theFileName As String = theProgress.FileName
If theProgress.Finished= True Then theMeta = ""


%>
<HTML>
<HEAD>
<title>Progress...</title>
<meta http-equiv="expires" content="Tue, 01 Jan 1981 01:00:00 GMT">
<% = theMeta %>
<script language="javascript">
<!--
if (<% = thePercent %> >= 100) top.close();
//-->
</script>
</HEAD>
<body bgcolor="#cccccc">
<table border="0" width="100%">
<tr>
<td><font face="Verdana, Arial, Helvetica, sans-serif" size="2"><b>Uploading:</b></font></td>
</tr>
<tr bgcolor="#999999">
<td>
<table border="0" width="<% = thePercent %>%" cellspacing="1" bgcolor="#0033ff">
<tr>
<td><font size="1">&nbsp;</font></td>
</tr>
</table>
</td>
</tr>
<tr>
<td>
<table border="0" width="100%">
<tr>
<td><font face="Verdana, Arial, Helvetica, sans-serif" size="1">Estimated time left:</font></td>
<td><font face="Verdana, Arial, Helvetica, sans-serif" size="1">
<% = theMins %> min
<% = theSecs %> secs
(<% = theKbdone %> KB of
<% = theKbtotal %> KB uploaded)
</font></td>
</tr>
<tr>
<td><font face="Verdana, Arial, Helvetica, sans-serif" size="1"> Transfer Rate:</font></td>
<td><font face="Verdana, Arial, Helvetica, sans-serif" size="1"><% = theKbps %> KB/sec</font></td>
</tr>
<tr>
<td><font face="Verdana, Arial, Helvetica, sans-serif" size="1">Information:</font></td>
<td><font face="Verdana, Arial, Helvetica, sans-serif" size="1"><% = theNote %></font></td>
</tr>
<tr>
<td><font face="Verdana, Arial, Helvetica, sans-serif" size="1">Uploading File:</font></td>
<td><font face="Verdana, Arial, Helvetica, sans-serif" size="1"><% = theFileName %></font></td>
</tr>
</table>
</td>
</tr>
<tr>
</tr>
</table>
</body>
</HTML>

 

   
ASP
 
global.asax    
     

In some situations you may wish to pick up progress events from within a global.asax file.

The progress database is stored in Application Scope and if your progress bar and upload page are being served from different web applications they may become disassociated from each other. This is not a normal situation but it can occur for some web site designs.

The most common situation in which this may occur is when operating from a web farm. In this scenario a page may be served from any one of a number of machines. So your upload page may be processed by one server while your progress bar is being served from another.

In this situation you may wish to store the upload state in an external store such as a database. This way you can code your progress bar to retrieve upload state from your shared store rather than from the standard Progress object.

In order to do this you need to pick up the progress update events which are sent out by ABCUpload and use them to update your shared store. You can do this using a handler within the global.asax file.

The particular form of shared store you want to use dictates how your code should be written. The example below is an illustrative example designed to show how a handler can be coded. It simply makes a log of all the progress events which are received.

[C#]
<%@ Import Namespace="WebSupergoo.ABCUpload6" %>

<script language="C#" runat="server">

public void Progress_UpdateProgress(object source, EventArgs e) {
  // this is an inefficient implementation but it illustrates how progress events can be captured
  // needless to say you should delete this handler or disable this logging for any live application
  string path = Server.MapPath("write/progress_log.txt");
  Progress state = ((ProgressEventArgs)e).State;
  System.IO.StreamWriter sw = new System.IO.StreamWriter(path, true);
  sw.BaseStream.Seek(0, System.IO.SeekOrigin.End);
  sw.WriteLine(state.ID.ToString() + " " + state.Note + " " + state.BytesDone.ToString() + " of " + state.BytesTotal.ToString());
  sw.Close();
}

</script>

[VB]
<%@ Import Namespace="WebSupergoo.ABCUpload6" %>

<script language="VB" runat="server">

Public Sub Progress_UpdateProgress(ByVal source As Object, ByVal e As EventArgs)
  ' this is an inefficient implementation but it illustrates how progress events can be captured
  ' needless to say you should delete this handler or disable this logging for any live application
  Dim path As String = Server.MapPath("write/progress_log.txt")
  Dim state As Progress = (CType(e, ProgressEventArgs)).State
  Dim sw As System.IO.StreamWriter = New System.IO.StreamWriter(path,True)
  sw.BaseStream.Seek(0, System.IO.SeekOrigin.End)
  sw.WriteLine(state.ID.ToString() + " " + state.Note + " " + state.BytesDone.ToString() + " of " + state.BytesTotal.ToString())
  sw.Close()
End Sub

</script>