0

I am developing an application for my own, In fact this application is for downloading latest version of antivirus that we are using in our company
in this application I want to use DownloadFileAsync method for download my files but it's not working and I am getting this error :

WebClient does not support concurrent I/O operations.

this is my source code :

private static WebClient wc = new WebClient();
        private static ManualResetEvent handle = new ManualResetEvent(true);
        private DateTime myDate = new DateTime();
        private void btn_test_Click(object sender, EventArgs e)
        {

            using (WebClient client = new WebClient())
            {
                client.Encoding = System.Text.Encoding.UTF8;
                var doc = new HtmlAgilityPack.HtmlDocument();
                ArrayList result = new ArrayList();
                doc.LoadHtml(client.DownloadString("https://www.symantec.com/security_response/definitions/download/detail.jsp?gid=savce"));
                foreach (var href in doc.DocumentNode.Descendants("a").Select(x => x.Attributes["href"]))
                {
                    if (href == null) continue;
                    string s = href.Value;
                    Match m = Regex.Match(s, @"http://definitions.symantec.com/defs/(\d{8}-\d{3}-v5i(32|64)\.exe)");
                    if (m.Success)
                    {
                        Match date = Regex.Match(m.Value, @"(\d{4})(\d{2})(\d{2})");
                        Match filename = Regex.Match(m.Value, @"\d{8}-\d{3}-v5i(32|64)\.exe");
                        int year = Int32.Parse(date.Groups[0].Value);
                        int month = Int32.Parse(date.Groups[1].Value);
                        int day = Int32.Parse(date.Groups[3].Value);

                        myDate = new DateTime(
                                Int32.Parse(date.Groups[1].Value),
                                Int32.Parse(date.Groups[2].Value),
                                Int32.Parse(date.Groups[3].Value));
                        listBox1.Items.Add(m.Value);
                        if (myDate == DateTime.Now)
                        {
                            Download(m.Value,filename.Value);

                        }
                        else
                        {
                            MessageBox.Show("There is no Update!");
                        }
                    }
                }

            }
        }
        private void Download(string url, string fileName)
        {
            wc.DownloadProgressChanged += new DownloadProgressChangedEventHandler(wc_DownloadProgressChanged);
            wc.DownloadFileAsync(new Uri(url), @"\\10.1.0.15\Symantec Update Weekly\\" + fileName);
            //wc.DownloadFile(url, @"\\10.1.0.15\Symantec Update Weekly\\" + fileName);
        }

        private void WcOnDownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
        {
            if (!e.Cancelled && e.Error == null)
            {
                //async download completed successfully
            }
            handle.Set();
        }

        private void wc_DownloadProgressChanged(object sender, System.Net.DownloadProgressChangedEventArgs e)
        {
            double bytesIn = double.Parse(e.BytesReceived.ToString());
            double totalBytes = double.Parse(e.TotalBytesToReceive.ToString());
            double percentage = bytesIn / totalBytes * 100;
            progressBar1.Value = int.Parse(Math.Truncate(percentage).ToString());
        } 

when my application trying to download files,
it seems that above method can not download multiple files in same time.
I searched a lot and find this solution but I could not apply that into my application.
how can I solve that.
thanks in your advise.

Community
  • 1
  • 1
Sirwan Afifi
  • 10,654
  • 14
  • 63
  • 110

1 Answers1

3
// Declare a field to hold the Task
private static Task DownloadTask;

private Task Download(string url, string fileName)
{
    var wc = new WebClient();
    wc.DownloadProgressChanged += new DownloadProgressChangedEventHandler(wc_DownloadProgressChanged);
    return wc.DownloadFileTaskAsync(new Uri(url), @"\\10.1.0.15\Symantec Update Weekly\\" + fileName);
}

You'll probably need change the progressbar to handle multiple threads.

Inside btn_test_Click

// Before foreach
var tasks = new List<Task>();

// Inside foreach
if (myDate == DateTime.Now)
{
    MessageBox.Show("Updates are New");
}
else
{
    tasks.Add(Download(m.Value,filename.Value));
}

// After foreach
// You can also set the TimeSpan value and update the progressbar
// periodically until all the tasks are finished
DownloadTask = Task.WhenAll(tasks);

See Task.WaitAll, WebClient.DownloadFileTaskAsync

Dustin Kingen
  • 20,677
  • 7
  • 52
  • 92
  • thanks, but I am getting this error : Cannot implicitly convert type 'void' to 'System.Threading.Tasks.Task' inside Download method line 'return...' – Sirwan Afifi Jun 12 '13 at 13:18
  • Sorry change the `DownloadFileAsync` to `DownloadFileTaskAsync`. See [`WebClient.DownloadFileTaskAsync`](http://msdn.microsoft.com/en-us/library/hh193917.aspx) – Dustin Kingen Jun 12 '13 at 13:21
  • thanks a lot it is working, but when I click btn_test_Click my application hangs and not responding to input Whereas it downloading my files, and another problem is about progress bar(nothing apprear) – Sirwan Afifi Jun 12 '13 at 13:26
  • You're going to need to refactor the progressbar to handle the concurrent downloads (and make sure all updates are on the `Dispatcher` thread). I've put in an edit for unblocking the UI thread (use `Task.WhenAll`). – Dustin Kingen Jun 12 '13 at 13:40