c# WebClient DownloadProgresschanged TotalBytesToReceive = -1 - c#

I've had a look around the web and can't see anyone else with this problem. I'm using a web client using DownloadFileAsync and when the event handler (DownloadProgressChanged) is called the TotalBytesToReceive (from the DownloadProgressChangedArgs) is equalling -1 for some reason, thus stopping me from being able to use a progress bar. I'm detecting <0 and if so just guessing 100meg for now, to get round it.
The BytesRecieved is working however, and the file is actually being downloaded, and the AsynCompletedEventHadnler seems to be getting called so it knows its finished (so must know the TotalBytesToReceive somehow?).
I'm using a WebClient with credentials and proxy credentials to download from a password protected external site going through an internal network (so needed both) - not sure if that would make any difference.
I was previously using WebClient.DownloadData getting the byte data and saving it separately and putting it in a background worker,and it worked fine (if quite slow) but there was no way I could show progress this way. Also the DownloadFileAsync seems to do all of this for me so saved a lot of code.
private void DLFile_AsyncWithStatus(string DLlocation, string un, string pw, string destLoc)
{
WebClient wc = new WebClient();
wc.Credentials = new NetworkCredential(un, pw); // website login
wc.Proxy.Credentials = new NetworkCredential(ProxyUsername, ProxyPassword, ProxyDomain); //proxy login
Uri uri = new Uri(DLlocation);
// Specify that the DownloadFileCallback method gets called when the download completes.
wc.DownloadFileCompleted += new AsyncCompletedEventHandler(DLFile_AsynWithStatus_Completed);
// Specify a progress notification handler.
wc.DownloadProgressChanged += new DownloadProgressChangedEventHandler(DownloadProgressCallback);
try
{
wc.DownloadFileAsync(uri, destLoc);
}
catch (WebException e)
{
MessageBox.Show(e.Message);
}
}
private void DownloadProgressCallback(object sender, DownloadProgressChangedEventArgs e)
{
double bytesIn = double.Parse(e.BytesReceived.ToString());
double totalBytes = double.Parse(e.TotalBytesToReceive.ToString());
if (totalBytes < 0) {
totalBytes = 100.0 * 1000000.0; //guess 100 meg since it is not detecting total bytes
}
double percentage = bytesIn / totalBytes * 100;
lblTmpStatus.Text = "Downloaded " + e.BytesReceived + " of " + e.TotalBytesToReceive;
progressBar1.Value = int.Parse(Math.Truncate(percentage).ToString());
}
void DLFile_AsynWithStatus_Completed(object sender, AsyncCompletedEventArgs e)
{
if (e.Error != null)
{
Msg(e.Error.Message);
}
else
{
progressBar1.Value = 100;//temp.. finish it off incase was less than 100 meg.
}
}

Related

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;
}

Download Multiple file, one by one using DownloadFileAsync in C#

How can I download multiple files, one by one. Using my code.
//Download File
public void DownloadFile(string url, string folderfile)
{
WebClient wc = new WebClient();
try
{
wc.DownloadFileCompleted += new AsyncCompletedEventHandler(DownloadCompleted);
wc.DownloadProgressChanged += new DownloadProgressChangedEventHandler(DownloadChanged);
wc.DownloadFileAsync(new Uri(url), folderfile);
}
catch (Exception ex)
{
MessageBox.Show("Error: \n\n" + ex.Message);
}
}
private void DownloadChanged(object sender, DownloadProgressChangedEventArgs e)
{
double bytesIn = double.Parse(e.BytesReceived.ToString());
double totalBytes = double.Parse(e.TotalBytesToReceive.ToString());
double percentage = bytesIn / totalBytes * 100.0;
int percente = int.Parse(Math.Truncate(percentage).ToString());
PBar.Value = percente;
progress.Text = percente + " %";
size.Text = string.Format("{0} MB / {1} MB", (e.BytesReceived / 1024d / 1024d).ToString("0.00"), (e.TotalBytesToReceive / 1024d / 1024d).ToString("0.00"));
}
private void DownloadCompleted(object sender, AsyncCompletedEventArgs e)
{
if (e.Error != null)
{
MessageBox.Show("Erro: " + e.Error.Message);
}
else
{
info.Text = "Download Success.";
}
}
public void CheckFileDownload()
{
string urlGame = "http://localhost/";
string Game = "Game.exe";
string Support = "Support.Xml";
string Info = "Info.xml";
if (!File.Exists(Game))
{
//Download Game
DownloadFile(urlGame + Game, Game);
info.Text = "Downloading: " + Game;
//If the game is downloading full
DownloadFile(urlGame + Info, Info);
DownloadFile(urlGame + Support, Support);
info.Text = "Updating information...";
}
}
private void Launcher_Load(object sender, EventArgs e)
{
CheckFileDownload();
}
Because I need to update the checkpoint file, after you download the Game.
I looked at several topics, but without success.
Thank everyone who helped me ... Sorry for my bad English
Thank you to all that help me. I will be very grateful...
If performance is not an issue, you can use DownloadFile and then it will download them in the sequence you specify and you don't need to bother with all the overlapping asynchronous operations. Since you're only downloading 3 files, the time savings of async coding is probably not worth it.
Alternately you could define flags for each file you intend to download (at the class level, not inside any of your functions), which could be in a Dictionary or just 3 bool variables. In DownloadFilAsync documentation note the userToken argument, which you use to identify which of the 3 files is done downloading. Use that to set the completed flags; then when the last download is complete, you carry on with whatever happens next.

ProgressBar progress change with all files that need to be downloaded

I'm making a WPF application where I use WebClient to download files form a webserver. I have a list of URL's with all the files i have to download. I use a foreach to loop through every URL and download each one at the time. The first URL much be completed before moving to the next one. I know the size of each file. Is there a way where I can set my e.ProgressPercentage to know the size of all files instead of loading from 0 to 100% for each file. I know that I'm calling DownloadProtocol for each URL right now, which makes a new instance of WebClient, but it is the only way I can think of to fulfill my solution, which is to download one file at a time.
public DownloadStart()
{
foreach(var url in ListOfDownloadURL)
{
DownloadGameFile dlg = new DownloadGameFile();
await dlg.DownloadProtocol(url, myLocation);
}
}
Download function in DownloadGameFile class:
public async Task DownloadProtocol(string address, string location)
{
Uri Uri = new Uri(address);
using (WebClient client = new WebClient())
{
//client.DownloadFileCompleted += new AsyncCompletedEventHandler(Completed);
//client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(DownloadProgress);
client.DownloadProgressChanged += (o, e) =>
{
Console.WriteLine(e.BytesReceived + " " + e.ProgressPercentage);
//ProgressBar = e.ProgressPercentage (total)
};
client.DownloadFileCompleted += (o, e) =>
{
if (e.Cancelled == true)
{
Console.WriteLine("Download has been canceled.");
}
else
{
Console.WriteLine("Download completed!");
}
};
await client.DownloadFileTaskAsync(Uri, location);
}
}
Why not take the easy way out and just update the progress when file is completed? Something like...
ProgressBar p = new ProgressBar();
p.Maximum = ListOfDownloadURL.Count();
foreach(var url in ListOfDownloadURL)
{
DownloadGameFile dlg = new DownloadGameFile();
await dlg.DownloadProtocol(url, myLocation);
p.Value += 1;
}
Or if you insist, you could query file sizes before you begin downloading, sum total bytes of all the files and then calculate the percentage when ever DownloadProgressChanged is fired.
var bytes = Convert.ToInt64(client.ResponseHeaders["Content-Length"]);

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.

How to update a view without waiting for another operation to finish

lets say I have a GroupBox with several Labels. In these Labels, various IP-related information are displayed. One info is the external IP address of the machine.
string externalIP = "";
try
{
WebRequest request = WebRequest.Create("http://checkip.dyndns.org/");
request.Timeout = 3000;
System.Threading.Tasks.Task<System.Net.WebResponse> response = request.GetResponseAsync();
using (StreamReader stream = new StreamReader(response.Result.GetResponseStream()))
{
if (response.Result.ContentLength != -1)
{
externalIP = stream.ReadToEnd();
}
}
}
catch (Exception e)
{
externalIP = "Error.";
}
if (externalIP == "")
{
return "No service.";
}
else
{
return externalIP = (new Regex(#"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}")).Matches(externalIP)[0].ToString();
}
This method is called from following code:
private void updateNetworkIP()
{
string ip4e = "External IPv4: " + getExternalIPv4();
lblIP4external.Text = ip4e;
//Get some more info here.
}
How do I execute the code after getExternalIPv4() even when it's not finished yet? It works when setting a TimeOut like I did above but sometimes the request just takes a little longer but still completes successfully. So I want to still be able to display the external IP but continue to execute the other methods for refreshing the GroupBox.
The BackgroundWorker will deliver what you are after. Sample code:
BackgroundWorker bg = new BackgroundWorker();
bg.DoWork += new DoWorkEventHandler(getExternalIPv4Back);
bg.RunWorkerCompleted += new RunWorkerCompletedEventHandler(writeLabel);
bg.RunWorkerAsync();
//The code below this point will be executed while the BackgroundWorker does its work
You have to define getExternalIPv4Back as a DoWork Event Method and include inside it the code to be executed in parallel; also writeLabel as a RunWorkerCompleted Event(required to edit the label without provoking muti-threading-related errors). That is:
private void getExternalIPv4Back(object sender, DoWorkEventArgs e)
{
IP = "External IPv4: " + getExternalIPv4(); //IP -> Globally defined variable
}
private void writeLabel(object sender, RunWorkerCompletedEventArgs e)
{
  lblIP4external.Text = IP;
}

Categories

Resources