-1

What i want is to start to download the first image save it to the hard disk. Once the download is completed and the progressBar got to 100% start to download the next image. And so on.

I tried this:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.Net;

namespace SatelliteImages
{
    public partial class Form1 : Form
    {
        int count = 0;

        public Form1()
        {
            InitializeComponent();

            ExtractImages ei = new ExtractImages();
            ei.Init();

            startDownload();
        }

        private void startDownload()
        {
            WebClient client = new WebClient();
            client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
            client.DownloadFileCompleted += new AsyncCompletedEventHandler(client_DownloadFileCompleted);
            foreach (string url in ExtractImages.imagesUrls)
            {
                client.DownloadFileAsync(new Uri(url), @"C:\Temp\TestingSatelliteImagesDownload\" + count + ".jpg");
            }
        }

        void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
        {
            double bytesIn = double.Parse(e.BytesReceived.ToString());
            double totalBytes = double.Parse(e.TotalBytesToReceive.ToString());
            double percentage = bytesIn / totalBytes * 100;
            label1.Text = "Downloaded " + e.BytesReceived + " of " + e.TotalBytesToReceive;
            progressBar1.Value = int.Parse(Math.Truncate(percentage).ToString());
        }
        void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
        {
            label1.Text = "Completed";
            count++;
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }
    }
}

The List imagesUrls contain links like this format for example the first item:

http://www.sat24.com/image2.ashx?region=eu&time=201612281630&ir=true

If i will browse to this link in chrome it will be fine. But when i'm trying to download the image and save the image on the hard disk i'm getting exception on the line:

client.DownloadFileAsync(new Uri(url), @"C:\Temp\TestingSatelliteImagesDownload\" + count + ".jpg");

Additional information: WebClient does not support concurrent I/O operations.

System.NotSupportedException was unhandled
  HResult=-2146233067
  Message=WebClient does not support concurrent I/O operations.
  Source=System
  StackTrace:
       at System.Net.WebClient.ClearWebClientState()
       at System.Net.WebClient.DownloadFileAsync(Uri address, String fileName, Object userToken)
       at System.Net.WebClient.DownloadFileAsync(Uri address, String fileName)
       at SatelliteImages.Form1.startDownload() in D:\C-Sharp\SatelliteImages\SatelliteImages\SatelliteImages\Form1.cs:line 37
       at SatelliteImages.Form1..ctor() in D:\C-Sharp\SatelliteImages\SatelliteImages\SatelliteImages\Form1.cs:line 27
       at SatelliteImages.Program.Main() in D:\C-Sharp\SatelliteImages\SatelliteImages\SatelliteImages\Program.cs:line 19
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: 
Moses Meteor
  • 365
  • 3
  • 12
  • 1
    http://stackoverflow.com/questions/25371743/await-multiple-file-downloads-with-downloaddataasync#25371913 – RamblinRose Dec 28 '16 at 18:43
  • 1
    See here: http://stackoverflow.com/questions/9765109/webclient-does-not-support-concurrent-i-o-operations - webclient doesnt allow multiple requests simultaneously. You will have to wrap it up as an async method that synchronously calls the webclient and returns the images. – Chris Watts Dec 28 '16 at 18:43
  • 3
    Have you looked at using `HttpClient` instead of `WebClient`? – Justin Skiles Dec 28 '16 at 18:44

2 Answers2

2

use DownloadFileTaskAsync for async download.

public event EventHandler TaskCompleted;

    public async void DownloadAsync()
    {
        String[] urls = { "http://media.salon.com/2014/10/shutterstock_154257524-1280x960.jpg",
                            "http://www.samsung.com/us/2012-smart-blu-ray-player/img/tv-front.png" };
        var tasks = urls.Select((url, index) =>
        {
            var fileName = String.Format(@"c:\temp\image-{0}.jpg", index);
            var client = new WebClient();
            return client.DownloadFileTaskAsync(url, fileName);
        });
        await Task.WhenAll(tasks).ContinueWith(x =>
        {
            if (TaskCompleted != null)
            {
                TaskCompleted(this, EventArgs.Empty);
            }
        });
    }
Ahmad Baig
  • 21
  • 3
1

you can only use the webclient instance until is is not busy because it not support concurrent call. So you must use a new WebClient instance for each download or chain the call after each download endend like this :

  //On initialize form :
        WebClient client = new WebClient();

   //On start download :

        client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
        client.DownloadFileCompleted += new AsyncCompletedEventHandler(client_DownloadFileCompleted);
        client.DownloadFileAsync(new Uri(url), @"C:\Temp\TestingSatelliteImagesDownload\" + ExtractImages.imagesUrls[currentImageIndex] + ".jpg");
 ...
        void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
        {
if(currentImageIndex<ImageToDownloadCount){
currentImageIndex +=1;
        client.DownloadFileAsync(new Uri(url), @"C:\Temp\TestingSatelliteImagesDownload\" + ExtractImages.imagesUrls[currentImageIndex] + ".jpg");
}

            label1.Text = "Completed";
            count++;
        }

Hope it helps.

Dypso
  • 563
  • 1
  • 5
  • 15