1

I'm having a problem with WebClient where WebClient.DownloadFileAsync is not reporting DownloadProgressChangedEventArgs until right before AsyncCompletedEventHandler is fired.

I have a method downloadFileAsync implemented in a class called HTTP in a dll called Test.dll. It basically amounts to running WebClient.DownloadFileAsync(new Uri(URL), downloadLocation);

Here is the test code I'm using to wrap around it.

Program.cs just does this:

namespace DL1
{
    class Program
    {
        static void Main(string[] args)
        {
            FLFront start = new FLFront();
        }
    }
}

FLFront.cs is this:

using System;
using System.ComponentModel;
using System.IO;
using System.Net;
using System.Text;
using System.Threading;
using System.Timers;
using Test;

namespace DL1
{
    class FLFront
    {
        static HTTP dlMGR;
        static Boolean downloadingCurrently = false;
        static System.Timers.Timer canDLChecker = new System.Timers.Timer();
        public FLFront()
        {
            SpecialWebClient swc = new SpecialWebClient();
            swc.setAmazonArt();
            dlMGR = new HTTP(swc);
                dlMGR.downloadJobs.Enqueue(@"http://downloads.sourceforge.net/project/sevenzip/7-Zip/9.20/7z920-x64.msi?r=http%3A%2F%2Fwww.7-zip.org%2Fdownload.html&ts=1325195085&use_mirror=superb-dca2");
                //dlMGR.downloadJobs.Enqueue(@"http://www.ubuntu.com/start-download?distro=desktop&bits=64&release=latest");
                dlMGR.downloadJobs.Enqueue(@"http://ftp.heanet.ie/mirrors/damnsmalllinux.org/current/dsl-4.4.10-initrd.iso");

                dlMGR.swc.DownloadFileCompleted += new AsyncCompletedEventHandler(dlCompleted);
                dlMGR.swc.DownloadProgressChanged += new DownloadProgressChangedEventHandler(dlProgress);


                canDLChecker.Elapsed += new ElapsedEventHandler(downloadFile);
                canDLChecker.Interval = 500;
                canDLChecker.Enabled = true;

                Thread.Sleep(3000000);
            }

            void dlCompleted(object sender, AsyncCompletedEventArgs e)
            {
                downloadingCurrently = false;
                if (File.Exists(dlMGR.downloadLocation))
                {
                    FileInfo dlInfo = new FileInfo(dlMGR.downloadLocation);
                    Console.WriteLine("Received Size: " + dlInfo.Length.ToString() + " Bytes");
                    if (dlInfo.Length == dlMGR.responseContentLength)
                    {
                        //downloadLocation.ren
                        //Console.WriteLine("Error: This file was not downloaded for some reason");
                        Console.WriteLine("File successfully downloaded.");
                        File.Move(dlMGR.downloadLocation, dlMGR.downloadLocation.Replace(".part", ""));
                    }
                    else
                    {
                        Console.WriteLine("File size mismatch.");
                    }
                }
                else
                    Console.WriteLine("File doesn't exist");
            }

            void dlProgress(object sender, DownloadProgressChangedEventArgs e)
            {
                //Console.WriteLine(e.BytesReceived);
                Console.WriteLine(e.ProgressPercentage + "%  ");
            }

            void downloadFile()
            {
                if (!downloadingCurrently)
                {
                    if (dlMGR.downloadJobs.Count > 0)
                    {

                        downloadingCurrently = true;
                        Console.WriteLine("Download starting: " + dlMGR.downloadJobs.Peek());
                        StringBuilder dlResult = dlMGR.downloadFileAsync(dlMGR.downloadJobs.Dequeue(), @"C:\", LoggingLevel.ErrorsOnly);
                        Console.Write(dlResult.ToString());
                        if (dlResult.ToString().Contains("Error: "))
                            dlFailed();
                    }
                    else
                    {
                        Console.WriteLine("No more download jobs exist. Exiting now.");
                        Environment.Exit(0);
                    }
                }
            }

            void downloadFile(object source, ElapsedEventArgs e)
            {
                downloadFile();
                //Console.WriteLine("Check Occurred");
            }

            void dlFailed()
            {
                downloadingCurrently = false;
                Console.WriteLine("Download Failed.");
            }
        }
    }

I just have some test files in there right now, but the code isn't reporting any progress until the files are basically done downloading.

Thoughts on why it's not reporting progress?

cvocvo
  • 1,586
  • 2
  • 23
  • 38
  • Where do you start the download? What does `HTTP` class do? How does `SpecialWebClient` implement `WebClient`? And why do you sleep the thread for so long? The following code works just fine. `WebClient wc = new WebClient(); wc.DownloadProgressChanged += (sender, e) => { }; wc.DownloadFileAsync(new Uri("some-file"), @"d:\somefile");` – Tomislav Markovski Dec 29 '11 at 23:07
  • Sounds like a classic case of the test-effect to me. Avoid testing your code with the same url over and over again. Otherwise reboot the machine and clear the IE cache to get representative results. – Hans Passant Dec 29 '11 at 23:24
  • HTTP is just a front-end class for some methods that make using WebClient easier. SpecialWebClient is just an extended class that lets WebClient store a cookie. – cvocvo Dec 29 '11 at 23:31
  • Solution: I found that inside my downloadFileAsync method in my HTTP class I was doing the same thing described here: http://stackoverflow.com/questions/8373368/downloaded-file-using-webclient-downloadfileasync-has-0kb Basically I was using a HttpWebRequest to get the Content-Length header and a HttpWebResponse to read what I got. The problem was that I didn't Close() the HttpWebResponse. That fixed some downloading issues where my files would be 0KB and WebClient.DownloadFileAsync would appear to hang AND it solved this issue where the events were not getting populated. – cvocvo Dec 29 '11 at 23:32
  • It's worthy to note here that without the Close() being called it did download the files but produced the problem described in this question while Fiddler was running. – cvocvo Dec 29 '11 at 23:32
  • @cvocvo - suggest you post your "solution" as an answer (below) to the question for others to read in the future. – Jeremy McGee Dec 30 '11 at 14:46

1 Answers1

0

Do the event assignments before you enqueue files for download. Also, remove the Thread.Sleep line it stops your current thread and your handlers are not hit because they are created within the same thread.

Tomislav Markovski
  • 12,331
  • 7
  • 50
  • 72
  • It's a console app...so the thread.sleep allowed it to stay open -- unneeded now. Assigning the event handlers before/after I add things to a Queue inside HTTP shouldn't matter. – cvocvo Dec 29 '11 at 23:26