Main | Custom Date Format Functions in SQL Server »

Friday, January 21, 2005

File Download with ProgressBar for Windows Forms

Note: Code is .NET 1.1

For a previous web project of mine, I built a web-based application update component that permitted the Webmaster to initiate software and database updates through a browser with a few button clicks (no manual file copy, etc...).

This of course involves having some sort of file download routine to copy the Update package from my server to a customer's server - and be managed through a Webform.

Downloading files in .NET is simple as a few lines of code using the WebClient or WebRequest and WebResponse Classes - but I also want to have a progress bar in the Webform.

Anyway, after much Googling for some sample code that included progress bars, the best I could find was some VB.NET examples for Windows Forms applications.

I found some working VB.NET code to download (credit to Mike McIntyre) from DevCity.NET. I transposed this VB.NET sample into C# (sample below), from which I'll base my ASP.NET implementation on (for another article) - allowing of course for how HTTP will push progress information to the Webform.

The credit also goes to this forum posting, where I think most of code originated. I just put it into a working Windows Forms application written in C#.

Downloadprogressbardemo

Download VS.NET 2003 C# Project - DemoDownloadProgressBar.zip (28.29 KB)

Following is an excerpt of the code.

private bool download(string path_download, string path_local){

    // Declare a variable of type Boolean named result initialized to false.
    bool result = false;
    // Declare a variable of type HttpWebRequest named lHttpWebRequest.
    HttpWebRequest lHttpWebRequest;
    // Declare a variable of type HttpWebResponse named lHttpWebResponse.
    HttpWebResponse lHttpWebResponse;
    // Declare a variable of type Stream named lHttpWebResponseStream.
    Stream lHttpWebResponseStream;
    // Declare a variable of type FileStream named lFileStream.
    // Use a FileStream constructor to create a new FileStream object.
    // Assign the address (reference) of the new object
    // to the lFileStream variable.
    FileStream lFileStream = new FileStream(path_local, FileMode.Create);
    // Declare a variable of type Byte Array named byteBuffer.
    byte[] byteBuffer = new byte[999];
    // Declare a variable of type Integer named bytesRead.
    int bytesRead;

    try{
        // Instantiate the HttpWebRequest object.
        lHttpWebRequest = (HttpWebRequest)WebRequest.Create(path_download);
        // Instantiate the HttpWebRespose object.
        lHttpWebResponse = (HttpWebResponse)lHttpWebRequest.GetResponse();
        // Instantiate the ResponseStream object.
        lHttpWebResponseStream = lHttpWebRequest.GetResponse().GetResponseStream();
        // Set the ProgressBars Maximum property equal to the length of the file
        // to be downloaded.
        progressBar1.Maximum = Convert.ToInt32(lHttpWebResponse.ContentLength);
        // progress counter to control when
        // the form label is updated
        double progress_counter = 0;

        do{

            // Read up to 1000 bytes into the bytesRead array.
            bytesRead = lHttpWebResponseStream.Read(byteBuffer, 0, 999);
            // Write the bytes read to the file stream.
            lFileStream.Write(byteBuffer, 0, bytesRead);
            // If the ProgressBar's value plus bytesRead is less than the length of the file...
            if((progressBar1.Value + bytesRead) <= progressBar1.Maximum){
                // Add bytesRead to the ProgressBar's Value property.
                progressBar1.Value += bytesRead;

            }else{
                // Else files download is done so set ProgressBar's Value to the length of the file.
                progressBar1.Value = progressBar1.Maximum;
            }
            // calculate the current percentage
            double progress_now = Math.Floor(((progressBar1.Value/100) * 100) / (progressBar1.Maximum/100));
            // only upgrade the display label once per percentage increment
            if(progress_now > progress_counter){
                // Update the ProgressLabel.
                label3.Text = String.Format("{0}% of {1}kb", progress_now.ToString(), (progressBar1.Maximum/1000).ToString("#,#"));
                // update the form
                Application.DoEvents();   
                // increment the counter
                progress_counter++;
            }

        }while(bytesRead > 0);

        // Close the file and web response streams.
        lHttpWebResponseStream.Close();
        // Set result to True - download was successful.
        result = true;

    }catch(Exception download_error){
        // display the whole error
        MessageBox.Show(download_error.ToString());
    }finally{
        // Close the file and web response streams.
        lFileStream.Close();
    }
    return result;
}

I changed a few things, like the percentage math for larger files. I was testing with a 38mb file and it caused some arithmetic errors on the huge decimal values it was creating. As well, I added a percentage counter so that the Label control was only updated once for each percent increment (about 100 times), as opposed to the 38,000,000 times the control was updated on my large test file, based on the original code.

Hope this is of use...

Note: This article is a repost from my original.

DemoDownloadProgressBar.zip

TrackBack

TrackBack URL for this entry:
http://www.typepad.com/t/trackback/1084389/6153121

Listed below are links to weblogs that reference File Download with ProgressBar for Windows Forms:

Comments

Nice site Scooter

Nice example!

However, I can't help but notice that the length of your comments greatly exceeds the length of the code you write.

"// Declare a variable of type HttpWebResponse named lHttpWebResponse.
HttpWebResponse lHttpWebResponse;"

A comment like that really adds no value and makes the code LESS readable, rather than the other way around.

Really!

Hey Erik, you're a dork!

You don't like it, then go get your code somewhere else.

Heartly thanks sir, you don't know how help ur code is for me. I am a software engineer working in Mobile Technology and new comer also. Once again thanks.

Regards,
Partha (The Name Everyone Needs)

Post a comment

If you have a TypeKey or TypePad account, please Sign In

Programmer for Hire

  • About Hiring Me:
  • Contact Information:
    • Name: P. Scott Cadillac
    • Phone: (902) 624-1266
    • Email: scott@xmlx.net
    • Location: Mahone Bay, Nova Scotia Canada
    • Timezone: Atlantic, ADT
  • Special Links: