Download file async using WebClient doens't work

16,738

Since Async calls do not block the current thread, my guess is that DownloadFileAsync (https://msdn.microsoft.com/en-us/library/ms144196(v=vs.110).aspx) returns immediately causing your DownloadFile to also return immediately. This will end program execution before the file can finish downloading.

You need to block the thread until the file has finished downloading. Have you considered using async/await from .NET 4.5 (https://msdn.microsoft.com/en-us/library/hh191443.aspx)? You can also use the Progress/Completed event to synchronize your thread so the app does not exit until the file has completed. Console.ReadLine() should also block the current thread until Enter is pressed.

I extended your code to support thread blocking. This will sleep the main thread for 1s between checks until the file has completed. I use the keyword "volatile" (https://msdn.microsoft.com/en-us/library/x13ttww7.aspx) to ensure that the newest value is always grabbed. This is important for multi threading. _completed = true is on the outside of the if/else because we want it to exit even if it was canceled. You can extend this solution to handle canceled downloads if you want.

class DownloadGamefile
{
    private volatile bool _completed;

    public void DownloadFile(string address, string location)
    {
        WebClient client = new WebClient();
        Uri Uri = new Uri(address);
        _completed = false;

        client.DownloadFileCompleted += new AsyncCompletedEventHandler(Completed);

        client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(DownloadProgress);
        client.DownloadFileAsync(Uri, location);

    }

    public bool DownloadCompleted { get { return _completed; } }

    private void DownloadProgress(object sender, DownloadProgressChangedEventArgs e)
    {
        // Displays the operation identifier, and the transfer progress.
        Console.WriteLine("{0}    downloaded {1} of {2} bytes. {3} % complete...",
            (string)e.UserState,
            e.BytesReceived,
            e.TotalBytesToReceive,
            e.ProgressPercentage);
    }

    private void Completed(object sender, AsyncCompletedEventArgs e)
    {
        if (e.Cancelled == true)
        {
            Console.WriteLine("Download has been canceled.");
        }
        else
        {
            Console.WriteLine("Download completed!");
        }

        _completed = true;
    }
}

class Program
{
    static void Main(string[] args)
    {

        DownloadGamefile DGF = new DownloadGamefile();

        DGF.DownloadFile("URL", @"C:\Users\LocDaiLe\Desktop\file.file");

        while (!DGF.DownloadCompleted)
            Thread.Sleep(1000);
    }
}
Share:
16,738
Loc Dai Le
Author by

Loc Dai Le

Updated on June 05, 2022

Comments

  • Loc Dai Le
    Loc Dai Le almost 2 years

    I'm making an Console application in VS15 using C#. Here is my downloading class:

    class DownloadGamefile
    {
        public  void DownloadFile(string address, string location)
        {
            WebClient client = new WebClient();
            Uri Uri = new Uri(address);
    
            client.DownloadFileCompleted += new AsyncCompletedEventHandler(Completed);
    
            client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(DownloadProgress);
            client.DownloadFileAsync(Uri, location);
    
        }
    
        private void DownloadProgress(object sender, DownloadProgressChangedEventArgs e)
        {
            // Displays the operation identifier, and the transfer progress.
            Console.WriteLine("{0}    downloaded {1} of {2} bytes. {3} % complete...",
                (string)e.UserState,
                e.BytesReceived,
                e.TotalBytesToReceive,
                e.ProgressPercentage);
        }
    
        private void Completed(object sender, AsyncCompletedEventArgs e)
        {
            if (e.Cancelled == true)
            {
                Console.WriteLine("Download has been canceled.");
            }
            else
            {
                Console.WriteLine("Download completed!");
            }
        }
    }
    

    and here is my main:

    class Program
    {
        static void Main(string[] args)
        {
    
            DownloadGamefile DGF = new DownloadGamefile();
    
            DGF.DownloadFile("URL", @"C:\Users\LocDaiLe\Desktop\file.file");
    
        }
    }
    

    The file appear in the right folder, but the size is 0bytes and my Console don't show any downloading progress.