WebClient multi file Downloader error - c#

im using the following code to download 50+ files from my webserver
private void button5_Click(object sender, EventArgs e)
{
WebClient client = new WebClient();
client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
client.DownloadFileCompleted += new AsyncCompletedEventHandler(client_DownloadFileCompleted);
//downloads
client.DownloadFileAsync(new Uri("http://www.site.com/file/loc.file"), #"c:\app\loc ");
client.DownloadFileAsync(new Uri("http://www.site.com/file/loc.file"), #"c:\app\loc ");
client.DownloadFileAsync(new Uri("http://www.site.com/file/loc.file"), #"c:\app\loc ");
}
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;
progressBar.Value = int.Parse(Math.Truncate(percentage).ToString());
}
private void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
MessageBox.Show("Game Update Finished!");
}
im wanting to download 1 file at a time with a continuing progress bar iv got most of the coding done but when i hit the "Download" button i get the following error
WebClient does not support concurrent I/O operations.
what do i need to do?

Feel the difference:
It CAN download multiple files in parallel manner (by one stream per
one file).
But it CAN'T download one file using multiple streams.
Here is example (MainWindow contain one button 'Start' and five progress bars):
public partial class MainWindow : Window
{
private WebClient _webClient;
private ProgressBar[] _progressBars;
private int _index = 0;
public MainWindow()
{
InitializeComponent();
_progressBars = new [] {progressBar1, progressBar2, progressBar3, progressBar4, progressBar5};
ServicePointManager.DefaultConnectionLimit = 5;
}
private void button1_Click(object sender, RoutedEventArgs e)
{
Interlocked.Increment(ref _index);
if (_index > _progressBars.Length)
return;
_webClient = new WebClient();
_webClient.DownloadProgressChanged += WebClient_DownloadProgressChanged;
_webClient.DownloadFileCompleted += WebClient_DownloadFileCompleted;
_webClient.DownloadFileAsync(new Uri("http://download.thinkbroadband.com/5MB.zip"),
System.IO.Path.GetTempFileName(),
_index);
}
private void WebClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs args)
{
var index = (int) args.UserState;
_progressBars[index-1].Value = args.ProgressPercentage;
}
private void WebClient_DownloadFileCompleted(object sender, AsyncCompletedEventArgs args)
{
var index = (int)args.UserState;
MessageBox.Show(args.Error == null
? string.Format("Download #{0} completed!", index)
: string.Format("Download #{0} error!\n\n{1}", index, args.Error));
}
}

you are running multiple downloads in parallel with the same WebClient instance - the error tells you that this is NOT supported - you either:
use multiple instances of WebClient (one per parallel download)
OR
download one file after the other
Relevant information:
http://msdn.microsoft.com/en-us/library/system.net.webclient.aspx
http://msdn.microsoft.com/en-us/magazine/cc700359.aspx

WebClient does not support concurrent I/O operations (multiple downloads) per instance, so you need to create a separate WebClient instance for each download. You can still perform each download asynchronously and use the same event handlers.

Related

DownloadFileAsync is blocking my App

I am trying to download a large file(around 1GB) my server.When I start downloading I am unable to use the app till the download completes. It is blocking the UI and its becoming unresponsive.
In below code I am calling DownloadFile method when the user download button on the UI.And then download starts, but the UI is freezed.
I read that DownloadFileAsync won't block the UI. But here its blocking. How to use it in correct way. There are several answers but none is working when I am testing.
Code:
Button call:
private void Button_Click(object sender, RoutedEventArgs e)
{
Debug.WriteLine("1");
DownloadGamefile DGF = new DownloadGamefile();
Debug.WriteLine("2" + Environment.CurrentDirectory);
DGF.DownloadFile("URL(https link to zip file)", Environment.CurrentDirectory + #"\ABC.zip");
Debug.WriteLine("3");
}
Download code:
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);
}
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;
}
}
Please refer to this link. The actual problem is getting lots of feedback about the number of bytes downloaded(about progress of download process). Take a timer to get progress for every 2 seconds or any time, this solved the problem.

c# webclient not timing out

Im trying to download files using extended WebClient with set timeout and I have a problem with the timeout (or what I think should cause timeout).
When I start the download with WebClient and receive some data, then disconnect wifi - my program hangs on the download without throwing any exception. How can I fix this?
EDIT: It actually throws exception but way later than it should (5 minutes vs 1 second which i set) - that is what Im trying to fix.
If you find anything else wrong with my code, please let me know too. Thank you for help
This is my extended class
class WebClientWithTimeout : WebClient
{
protected override WebRequest GetWebRequest(Uri address)
{
WebRequest w = base.GetWebRequest(address);
w.Timeout = 1000;
return w;
}
}
This is the download
using (WebClientWithTimeout wct = new WebClientWithTimeout())
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
try
{
wct.DownloadFile("https://example.com", file);
}
catch (Exception e)
{
Console.WriteLine("Download: {0} failed with exception:{1} {2}", file, Environment.NewLine, e);
}
}
Try this, you can avoid UI blocking by this. Coming the WiFi when device connects to WiFi the download resumes.
//declare globally
DateTime lastDownloaded = DateTime.Now;
Timer t = new Timer();
WebClient wc = new WebClient();
//declarewherever you initiate download my case button click
private void button1_Click(object sender, EventArgs e)
{
wc.DownloadProgressChanged += Wc_DownloadProgressChanged;
wc.DownloadFileCompleted += Wc_DownloadFileCompleted;
lastDownloaded = DateTime.Now;
t.Interval = 1000;
t.Tick += T_Tick;
wc.DownloadFileAsync(new Uri("https://github.com/google/google-api-dotnet-client/archive/master.zip"), #"C:\Users\chkri\AppData\Local\Temp\master.zip");
}
private void T_Tick(object sender, EventArgs e)
{
if ((DateTime.Now - lastDownloaded).TotalMilliseconds > 1000)
{
wc.CancelAsync();
}
}
private void Wc_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
if (e.Error != null)
{
lblProgress.Text = e.Error.Message;
}
}
private void Wc_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
lastDownloaded = DateTime.Now;
lblProgress.Text = e.BytesReceived + "/" + e.TotalBytesToReceive;
}

Run background worker in parallel with Webclient file download

I have a background worker used for running a time consuming sync operation with server and is working perfectly and UI is responsive during the operation
BackgroundWorker syncWorker = new BackgroundWorker();
syncWorker.WorkerReportsProgress = true;
syncWorker.DoWork += new DoWorkEventHandler(syncWorker_DoWork);
syncWorker.ProgressChanged += new ProgressChangedEventHandler(syncWorker_ProgressChanged);
syncWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(syncWorker_RunWorkerCompleted);
private void syncWorker_DoWork(object sender, DoWorkEventArgs e)
{
foreach (xxxx item in actives)
{
target.ReportProgress(progress);
//time taking event running fine here..
}
target.ReportProgress(90);
}
private void syncWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
lbl_progress.Text="Wait......";
}
private void syncWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
lbl_progress.Text="DONE!..";
}
Now i have to do a file download operation and i am using Webclient to do it using the code
WebClient downloadClient = new WebClient();
downloadClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(downloadClient_DownloadProgressChanged);
downloadClient.DownloadFileCompleted += new AsyncCompletedEventHandler(downloadClient_DownloadFileCompleted);
downloadClient.DownloadFileAsync(new Uri(fileUrl), download_path);
void downloadClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
double bytesIn = double.Parse(e.BytesReceived.ToString());
double totalBytes = double.Parse(e.TotalBytesToReceive.ToString());
double percentage = bytesIn / totalBytes * 100;
int progress_value = int.Parse(Math.Truncate(percentage).ToString());
progress_value = (progress_value < 5) ? 5 : (progress_value > 95) ? 95 : progress_value;
lblDownloadProgress.Content = string.Format("DOWNLOADING - {0}%", progress_value.ToString());
}
void downloadClient_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
string item = (string)e.UserState;
if (e.Error != null )
{
lblDownloadProgress.Content = "Unable to download.Try again.....";
lblDownloadProgress.Foreground = Brushes.Red;
}
else if (e.Cancelled)
{
//Do Nothing
}
else
{
lblDownloadProgress.Content ="DOWNLOADED..";
}
}
Now can i run these 2 things parallely ? Like run background worker while downlaoding the file??
if file downloading finished first wait till the completion of background worker
if background worker finished first wait till completion of download
Enable controls after both operations finished and keep UI responsive during the whole time
You can run 2 Background worker in parallel but if you need check the state of one of them you can check if the backgroundworker is busy(doing work or completed).
private void syncWorker_DoWork(object sender, DoWorkEventArgs e)
{
while( downloadClient.IsBusy)
{
Sleep(5000);
//waiting downloadClient worker to complete
}
//continue the work
}
look into this for check some trick you can do.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Threading;
namespace download_demo
{
class Program
{
static void Main(string[] args)
{
BackgroundWorker MyWorker = new BackgroundWorker();
MyWorker.DoWork += MyWorker_DoWork;
MyWorker.RunWorkerCompleted +=MyWorker_RunWorkerCompleted;
MyWorker.RunWorkerAsync();
Console.ReadKey();
}
private static void MyWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Console.WriteLine("both job completed");
}
private static void MyWorker_DoWork(object sender, DoWorkEventArgs e)
{
Thread download = new Thread(DownloadJob);
download.Start();
for (int i = 0; i < 5; i++)
{
Thread.Sleep(20);
Console.WriteLine("doing some job while downloading ");
}
Console.WriteLine("waiting the end of download......... ");
download.Join();
}
private static void DownloadJob(object path)
{
/// process download the path
///simulate 20 seconde of download
for(int i = 0;i<100;i++)
{
Thread.Sleep(50);
Console.WriteLine("downloaded :" + i + " Ko");
}
}
}
}

Downloading multiple files one at a time

This is the Code Below....
using System.Net;
//Create Temporary Folder to Holde All the Downloads............
namespace downloadFileCSharp10
{
public partial class Form1 : Form
{
string url = "URL";
string path = #"c:\Folder";
public Form1()
{
InitializeComponent();
}
void InitiateDownload(string RemoteAddress, string LocalFile, AsyncCompletedEventHandler CompleteCallBack, object userToken)
{
WebClient wc = new WebClient();
wc.DownloadProgressChanged += wc_DownloadProgressChanged;
wc.DownloadFileCompleted += wc_DownloadFileCompleted;
wc.DownloadFileAsync(new Uri(RemoteAddress), LocalFile, userToken);
}
void wc_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
if (e.Error != null)
{
lblInfo1.Visible = true;
lblInfo1.ForeColor = Color.Red;
lblInfo1.Text = "Error Downloading ";
//throw e.Error;
}
else if (e.Cancelled)
{
lblInfo1.Visible = true;
lblInfo1.ForeColor = Color.Red;
lblInfo1.Text = "Download Cancelled " + e.UserState + e.Error;
}
else
{
lblInfo1.Visible = true;
lblInfo1.ForeColor = Color.Red;
lblInfo1.Text = e.UserState + " Download Complete!! ";
}
//throw new NotImplementedException();
}
void wc_DownloadProgressChanged(object sender, 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());
label1.Text = e.ProgressPercentage.ToString() + "%";
//throw new NotImplementedException();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void btnGetDownload_Click(object sender, EventArgs e)
{
//First Download
InitiateDownload(URL, path + "name you give.txt", wc_DownloadFileCompleted, "name you give.txt");
//Second Download
InitiateDownload(URL, path + "name you give2.txt", wc_DownloadFileCompleted, "name you give2.txt");
}
}
}
When I download multiple files it downloads all at the same time and from time to time I get one or two downloads that become corrupted. Also when I have more than 10 or 15 my application freezes a bit because its downloading all at the same. I want to be able to download at at least one or two at a time. I have looked around in using async and await but had no luck with. In addition I want to put a progressbar for each download file. So basically a loop but inserted into a listview but do not know how to go about it or maybe how to approach it.
Can you check http://blogs.msdn.com/b/spike/archive/2013/06/12/how-to-download-multiple-files-concurrently-using-webclient-and-the-downloadfileasync-method.aspx.
As I understand you should configure simultaneous outgoing connection limit to a higher number.
In the App.config file for the project, add the maxconnection setting:
<?xmlversion="1.0"encoding="utf-8" ?>
<configuration>
<system.net>
<connectionManagement>
<addaddress = "*"maxconnection = "10" />
</connectionManagement>
</system.net>
</configuration>
Credits to upper link. But this can only explain freezes when large number of files requested. For file corruption I think another point needs to be solved.

why my WebClient upload file code hangs?

I am using VSTS 2008 + C# + .Net 3.5 + ASP.Net + IIS 7.0 to develop a Windows Forms application at client side to upload a file, and at server side I receive this file using an aspx file.
I find my client side application will hang after click the button to trigger upload event. Any ideas what is wrong and how to solve? Thanks!
Client side code,
public partial class Form1 : Form
{
private static WebClient client = new WebClient();
private static ManualResetEvent uploadLock = new ManualResetEvent(false);
private static void Upload()
{
try
{
Uri uri = new Uri("http://localhost/Default2.aspx");
String filename = #"C:\Test\1.dat";
client.Headers.Add("UserAgent", "TestAgent");
client.UploadProgressChanged += new UploadProgressChangedEventHandler(UploadProgressCallback);
client.UploadFileCompleted += new UploadFileCompletedEventHandler(UploadFileCompleteCallback);
client.UploadFileAsync(uri, "POST", filename);
uploadLock.WaitOne();
}
catch (Exception e)
{
Console.WriteLine(e.StackTrace.ToString());
}
}
public static void UploadFileCompleteCallback(object sender, UploadFileCompletedEventArgs e)
{
Console.WriteLine("Completed! ");
uploadLock.Set();
}
private static void UploadProgressCallback(object sender, UploadProgressChangedEventArgs e)
{
Console.WriteLine("{0} uploaded {1} of {2} bytes. {3} % complete...",
(string)e.UserState,
e.BytesSent,
e.TotalBytesToSend,
e.ProgressPercentage);
// Console.WriteLine (e.ProgressPercentage);
}
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Upload();
}
}
Server side code:
protected void Page_Load(object sender, EventArgs e)
{
string agent = HttpContext.Current.Request.Headers["UserAgent"];
using (FileStream file = new FileStream(#"C:\Test\Agent.txt", FileMode.Append, FileAccess.Write))
{
byte[] buf = Encoding.UTF8.GetBytes(agent);
file.Write(buf, 0, buf.Length);
}
foreach (string f in Request.Files.AllKeys)
{
HttpPostedFile file = Request.Files[f];
file.SaveAs("C:\\Test\\UploadFile.dat");
}
}
you are waiting in the main windows events thread, so your GUI will be frozen.
Try this (using non static methods allows you to use the Control.Invoke method to run callbacks on the windows GUI thread and free this thread in order to redraw)
public partial class Form1 : Form
{
private static WebClient client = new WebClient();
private static ManualResetEvent uploadLock = new ManualResetEvent(false);
private void Upload()
{
try
{
Cursor=Cursors.Wait;
Uri uri = new Uri("http://localhost/Default2.aspx");
String filename = #"C:\Test\1.dat";
client.Headers.Add("UserAgent", "TestAgent");
client.UploadProgressChanged += new UploadProgressChangedEventHandler(UploadProgressCallback);
client.UploadFileCompleted += new UploadFileCompletedEventHandler(UploadFileCompleteCallback);
client.UploadFileAsync(uri, "POST", filename);
}
catch (Exception e)
{
Console.WriteLine(e.StackTrace.ToString());
this.Cursor=Cursors.Default;
this.Enabled=false;
}
}
public void UploadFileCompleteCallback(object sender, UploadFileCompletedEventArgs e)
{
// this callback will be invoked by the async upload handler on a ThreadPool thread, so we cannot touch anything GUI-related. For this we have to switch to the GUI thread using control.BeginInvoke
if(this.InvokeRequired)
{
// so this is called in the main GUI thread
this.BeginInvoke(new UploadFileCompletedEventHandler(UploadFileCompleteCallback); // beginInvoke frees up the threadpool thread faster. Invoke would wait for completion of the callback before returning.
}
else
{
Cursor=Cursors.Default;
this.enabled=true;
MessageBox.Show(this,"Upload done","Done");
}
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Upload();
}
}
}
And do the same thing in your progress (you could update a progressbar indicator for example).
Cheers,
Florian

Categories

Resources