none
How to download files using webclient downloadfileasync ? RRS feed

  • Question

  • private void downloadsources()
            {
                string link = "https://www.myweb.com/";
    
                
    
                for (int i = 2; i < 141; i++)
                {
                    
                    sourcers.Add(link + "index" + i + ".html");
                }
    
                WebClient wc = new WebClient();
                wc.Headers.Add("User-Agent: Other");
                wc.DownloadFileCompleted += Wc_DownloadFileCompleted;
                wc.DownloadFileAsync(new Uri(sourcers[0]), @"e:\dr\htmlsources\source" + sourcers[0] + ".html");
    
                wc.Dispose();
            }
    
            private void Wc_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
            {
                WebClient wc = new WebClient();
    
                sourcers.RemoveAt(0);
    
                if(sourcers.Count > 0)
                {
                    wc.DownloadFileAsync(new Uri(sourcers[0]), @"e:\dr\htmlsources\source" + sourcers[0] + ".html");
                }
    
                wc.Dispose();
            }

    First I'm building the sources links. Then downloading. It's downloading the first source but then never continue.

    It's getting to the Wc_DownloadFileCompleted to line :

    wc.DownloadFileAsync(new Uri(sourcers[0]), @"e:\dr\htmlsources\source" + sourcers[0] + ".html");

    But then never continue.

    I want to download all the sourcers(Should be sources but never mind now).

    Thursday, April 2, 2020 2:17 AM

Answers

  • Hi Chocolade1972,

    There is a lot of code, and there are many custom classes and methods, so I can't test it.

    But I successfully downloaded all the files I want with the following code.

    You can try it.

            private async void button1_Click(object sender, EventArgs e)
            {
                using (FolderBrowserDialog fbd = new FolderBrowserDialog() { Description = "Select folder..." })
                {
                    if (fbd.ShowDialog() == DialogResult.OK)
                    {
                        List<string> list = new List<string>();
                        list.Add("https://www.codeproject.com/KB/miscctrl/ImageMagnifier/ImageMagnifier_src.zip");
                        list.Add("https://www.codeproject.com/KB/miscctrl/ImageMagnifier/ImageMagnifier_demo.zip");
                        list.Add("https://social.msdn.microsoft.com/Forums/getfile/1571453");
                        foreach (string url in list)
                        {
                            using (WebClient client = new WebClient())
                            {
                                client.Credentials = CredentialCache.DefaultNetworkCredentials;
                                Uri uri = new Uri(url);
                                string filename = System.IO.Path.GetFileName(uri.LocalPath);
                                await client.DownloadFileTaskAsync(uri,
                                    $"{fbd.SelectedPath}\\{filename}"
                                );
                            }
                        }
                        MessageBox.Show("You have finished downloading the file.", "Message", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    }
                }
            }

    Best Regards,

    Timon


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Friday, April 3, 2020 9:19 AM

All replies

  • Hi Chocolade1972,

    Thank you for posting here.

    According to the code, you only initiated one download request.

    "sourcers[0]" is a URL that appears to contain characters that are not supported as filenames.

    Also, could you tell us why do you initiate the download request again in the Wc_DownloadFileCompleted method?

    Best Regards,

    Timon


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Thursday, April 2, 2020 10:01 AM
  • I tried something else :

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Diagnostics;
    using System.Drawing;
    using System.IO;
    using System.Net;
    using System.Text;
    using System.Windows.Forms;
    
    // Much of this example drawn from: http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.begingetresponse.aspx
    
    namespace DownloadStressTest
    {
        // Callbacks to allow updating GUI during transfer or upon completion
        public delegate void ResponseInfoDelegate(string statusDescr, string contentLength);
        public delegate void ProgressDelegate(int totalBytes, double pctComplete, double transferRate);
        public delegate void DoneDelegate();
    
        /// <summary>
        /// Main form to allow downloading files via HTTP or FTP
        /// </summary>
        public partial class DownloadStressTestForm : Form
        {
            const int BUFFER_SIZE = 1448;	// TCP packet size if 1448 bytes (seen thru inspection)
    
            public DownloadStressTestForm()
            {
                InitializeComponent();
    
                lblDownloadComplete.Visible = false;
            }
    
            /// <summary>
            /// "Get File" button, which starts the transfer
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void btnGetFile_Click(object sender, EventArgs e)
            {
                List<string> urls = new List<string>();
                urls.Add("http://mschnlnine.vo.llnwd.net/d1/pdc08/PPTX/BB01.pptx");
                urls.Add("http://mschnlnine.vo.llnwd.net/d1/pdc08/PPTX/BB02.pptx");
    
                try
                {
                    for (int i = 0; i < urls.Count; i++)
                    {
                        txtURI.Text = urls[i];
                        btnGetFile.Enabled = false;
    
                        lblDownloadComplete.Visible = false;
    
                        WebRequest req = null;
                        WebRequestState reqState = null;
                        Uri fileURI = new Uri(urls[i]);//txtURI.Text);
    
                        if (fileURI.Scheme == Uri.UriSchemeHttp)
                        {
                            req = (HttpWebRequest)HttpWebRequest.Create(fileURI);
                            reqState = new HttpWebRequestState(BUFFER_SIZE);
                            reqState.request = req;
                        }
                        else if (fileURI.Scheme == Uri.UriSchemeFtp)
                        {
                            // Get credentials
                            GetCredentialsForm frmCreds = new GetCredentialsForm();
                            DialogResult result = frmCreds.ShowDialog();
                            if (result == DialogResult.OK)
                            {
                                req = (FtpWebRequest)FtpWebRequest.Create(fileURI);
                                req.Credentials = new NetworkCredential(frmCreds.Username, frmCreds.Password);
                                reqState = new FtpWebRequestState(BUFFER_SIZE);
    
                                // Set FTP-specific stuff
                                ((FtpWebRequest)req).KeepAlive = false;
    
                                // First thing we do is get file size.  2nd step, done later, 
                                // will be to download actual file.
                                ((FtpWebRequest)req).Method = WebRequestMethods.Ftp.GetFileSize;
                                reqState.FTPMethod = WebRequestMethods.Ftp.GetFileSize;
    
                                reqState.request = req;
                            }
                            else
                                req = null; // abort
    
                        }
                        else
                            MessageBox.Show("URL must be either http://xxx or ftp://xxxx");
    
                        if (req != null)
                        {
                            reqState.fileURI = fileURI;
                            reqState.respInfoCB = new ResponseInfoDelegate(SetResponseInfo);
                            reqState.progCB = new ProgressDelegate(Progress);
                            reqState.doneCB = new DoneDelegate(Done);
                            reqState.transferStart = DateTime.Now;
    
                            // Start the asynchronous request.
                            IAsyncResult result =
                              (IAsyncResult)req.BeginGetResponse(new AsyncCallback(RespCallback), reqState);
                        }
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(string.Format("EXC in button1_Click(): {0}", ex.Message));
                }
            }
    
            /// <summary>
            /// Response info callback, called after we get HTTP response header.
            /// Used to set info in GUI about max download size.
            /// </summary>
            private void SetResponseInfo(string statusDescr, string contentLength)
            {
                if (this.InvokeRequired)
                {
                    ResponseInfoDelegate del = new ResponseInfoDelegate(SetResponseInfo);
                    this.Invoke(del, new object[] { statusDescr, contentLength });
                }
                else
                {
                    lblStatusDescr.Text = statusDescr;
                    lblContentLength.Text = contentLength;
                }
            }
    
            /// <summary>
            /// Progress callback, called when we've read another packet of data.
            /// Used to set info in GUI on % complete & transfer rate.
            /// </summary>
            private void Progress(int totalBytes, double pctComplete, double transferRate)
            {
                if (this.InvokeRequired)
                {
                    ProgressDelegate del = new ProgressDelegate(Progress);
                    this.Invoke(del, new object[] { totalBytes, pctComplete, transferRate });
                }
                else
                {
                    lblBytesRead.Text = totalBytes.ToString();
                    progressBar1.Value = (int)pctComplete;
                    lblRate.Text = transferRate.ToString("f0");
                }
            }
    
            /// <summary>
            /// GUI-updating callback called when download has completed.
            /// </summary>
            private void Done()
            {
                if (this.InvokeRequired)
                {
                    DoneDelegate del = new DoneDelegate(Done);
                    this.Invoke(del, new object[] { });
                }
                else
                {
                    //progressBar1.Value = 0;
                    lblDownloadComplete.Visible = true;
                }
    
                btnGetFile.Enabled = true;
            }
    
            /// <summary>
            /// Main response callback, invoked once we have first Response packet from
            /// server.  This is where we initiate the actual file transfer, reading from
            /// a stream.
            /// </summary>
            private static void RespCallback(IAsyncResult asyncResult)
            {
                try
                {
                    // Will be either HttpWebRequestState or FtpWebRequestState
                    WebRequestState reqState = ((WebRequestState)(asyncResult.AsyncState));
                    WebRequest req = reqState.request;
                    string statusDescr = "";
                    string contentLength = "";
    
                    // HTTP 
                    if (reqState.fileURI.Scheme == Uri.UriSchemeHttp)
                    {
                        HttpWebResponse resp = ((HttpWebResponse)(req.EndGetResponse(asyncResult)));
                        reqState.response = resp;
                        statusDescr = resp.StatusDescription;
                        reqState.totalBytes = reqState.response.ContentLength;
                        contentLength = reqState.response.ContentLength.ToString();   // # bytes
                    }
    
                    // FTP part 1 - response to GetFileSize command
                    else if ((reqState.fileURI.Scheme == Uri.UriSchemeFtp) &&
                             (reqState.FTPMethod == WebRequestMethods.Ftp.GetFileSize))
                    {
                        // First FTP command was GetFileSize, so this 1st response is the size of 
                        // the file.
                        FtpWebResponse resp = ((FtpWebResponse)(req.EndGetResponse(asyncResult)));
                        statusDescr = resp.StatusDescription;
                        reqState.totalBytes = resp.ContentLength;
                        contentLength = resp.ContentLength.ToString();   // # bytes
                    }
    
                    // FTP part 2 - response to DownloadFile command
                    else if ((reqState.fileURI.Scheme == Uri.UriSchemeFtp) &&
                             (reqState.FTPMethod == WebRequestMethods.Ftp.DownloadFile))
                    {
                        FtpWebResponse resp = ((FtpWebResponse)(req.EndGetResponse(asyncResult)));
                        reqState.response = resp;
                    }
    
                    else
                        throw new ApplicationException("Unexpected URI");
    
    
                    // Get this info back to the GUI -- max # bytes, so we can do progress bar
                    if (statusDescr != "")
                        reqState.respInfoCB(statusDescr, contentLength);
    
                    // FTP part 1 done, need to kick off 2nd FTP request to get the actual file
                    if ((reqState.fileURI.Scheme == Uri.UriSchemeFtp) && (reqState.FTPMethod == WebRequestMethods.Ftp.GetFileSize))
                    {
                        // Note: Need to create a new FtpWebRequest, because we're not allowed to change .Method after
                        // we've already submitted the earlier request.  I.e. FtpWebRequest not recyclable.
                        // So create a new request, moving everything we need over to it.
                        FtpWebRequest req2 = (FtpWebRequest)FtpWebRequest.Create(reqState.fileURI);
                        req2.Credentials = req.Credentials;
                        req2.UseBinary = true;
                        req2.KeepAlive = true;
                        req2.Method = WebRequestMethods.Ftp.DownloadFile;
    
                        reqState.request = req2;
                        reqState.FTPMethod = WebRequestMethods.Ftp.DownloadFile;
    
                        // Start the asynchronous request, which will call back into this same method
                        IAsyncResult result =
                          (IAsyncResult)req2.BeginGetResponse(new AsyncCallback(RespCallback), reqState);
                    }
                    else	// HTTP or FTP part 2 -- we're ready for the actual file download
                    {
                        // Set up a stream, for reading response data into it
                        Stream responseStream = reqState.response.GetResponseStream();
                        reqState.streamResponse = responseStream;
    
                        // Begin reading contents of the response data
                        IAsyncResult ar = responseStream.BeginRead(reqState.bufferRead, 0, BUFFER_SIZE, new AsyncCallback(ReadCallback), reqState);
                    }
    
                    return;
                }
                catch (Exception ex)
                {
                    MessageBox.Show(string.Format("EXC in RespCallback(): {0}", ex.Message));
                }
            }
    
            /// <summary>
            /// Main callback invoked in response to the Stream.BeginRead method, when we have some data.
            /// </summary>
            private static void ReadCallback(IAsyncResult asyncResult)
            {
                try
                {
                    // Will be either HttpWebRequestState or FtpWebRequestState
                    WebRequestState reqState = ((WebRequestState)(asyncResult.AsyncState));
    
                    Stream responseStream = reqState.streamResponse;
    
                    // Get results of read operation
                    int bytesRead = responseStream.EndRead(asyncResult);
    
                    // Got some data, need to read more
                    if (bytesRead > 0)
                    {
                        // Report some progress, including total # bytes read, % complete, and transfer rate
                        reqState.bytesRead += bytesRead;
                        double pctComplete = ((double)reqState.bytesRead / (double)reqState.totalBytes) * 100.0f;
    
                        // Note: bytesRead/totalMS is in bytes/ms.  Convert to kb/sec.
                        TimeSpan totalTime = DateTime.Now - reqState.transferStart;
                        double kbPerSec = (reqState.bytesRead * 1000.0f) / (totalTime.TotalMilliseconds * 1024.0f);
    
                        reqState.progCB(reqState.bytesRead, pctComplete, kbPerSec);
    
                        // Kick off another read
                        IAsyncResult ar = responseStream.BeginRead(reqState.bufferRead, 0, BUFFER_SIZE, new AsyncCallback(ReadCallback), reqState);
                        return;
                    }
    
                    // EndRead returned 0, so no more data to be read
                    else
                    {
                        responseStream.Close();
                        reqState.response.Close();
                        reqState.doneCB();
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(string.Format("EXC in ReadCallback(): {0}", ex.Message));
                }
            }
    
            /// <summary>
            /// When we load form, clear out design-time labels.
            /// </summary>
            private void DownloadStressTestForm_Load(object sender, EventArgs e)
            {
                // Clean out design-time labels
                lblStatusDescr.Text = "";
                lblContentLength.Text = "";
                lblBytesRead.Text = "";
                lblRate.Text = "";
            }
        }
    }

    But I have two problems : 

    1. I'm downloading for testing two files using a loop over the List urls inside btnGetFile_Click but it's not showing the first file BB01 in the textBox txtURI.Text it's only show there BB02. 

    2. When using the loop and trying to download two files the data info in the Progress is not fine.  Seems like it's not updating for more then one file download.

    3. How can I save the downloaded file/s to the hard disk ? Now it's downloading the file/s to memory and destroy them. Here is a quoting from the owner of this code :  "Sure, my example reads the data into the buffer in WebRequestState, so you could just access that data from the ReadCallback method, as each packet becomes available." But I don't understand how to do it and save the file/s.

    What I want to do is that when clicking the Get File button (btnGetFile) it will download multiple files from List<string> of urls.

    Here is a screenshot after it finished downloading the two files BB01 and BB02 the data info is not right and it didn't save the files to the hard disk and not sure if my loop is fine :

    Thursday, April 2, 2020 11:58 AM
  • Hi Chocolade1972,

    There is a lot of code, and there are many custom classes and methods, so I can't test it.

    But I successfully downloaded all the files I want with the following code.

    You can try it.

            private async void button1_Click(object sender, EventArgs e)
            {
                using (FolderBrowserDialog fbd = new FolderBrowserDialog() { Description = "Select folder..." })
                {
                    if (fbd.ShowDialog() == DialogResult.OK)
                    {
                        List<string> list = new List<string>();
                        list.Add("https://www.codeproject.com/KB/miscctrl/ImageMagnifier/ImageMagnifier_src.zip");
                        list.Add("https://www.codeproject.com/KB/miscctrl/ImageMagnifier/ImageMagnifier_demo.zip");
                        list.Add("https://social.msdn.microsoft.com/Forums/getfile/1571453");
                        foreach (string url in list)
                        {
                            using (WebClient client = new WebClient())
                            {
                                client.Credentials = CredentialCache.DefaultNetworkCredentials;
                                Uri uri = new Uri(url);
                                string filename = System.IO.Path.GetFileName(uri.LocalPath);
                                await client.DownloadFileTaskAsync(uri,
                                    $"{fbd.SelectedPath}\\{filename}"
                                );
                            }
                        }
                        MessageBox.Show("You have finished downloading the file.", "Message", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    }
                }
            }

    Best Regards,

    Timon


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Friday, April 3, 2020 9:19 AM
  • Hi,

    Has your issue been resolved?

    If so, please click "Mark as answer" to the appropriate answer, so that it will help other members to find the solution quickly if they face a similar issue.

    Best Regards,

    Timon


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Thursday, April 9, 2020 8:46 AM