UploadProgressChanged with Foreach - c#

Ok, I have this:
foreach (FileInfo fileinfo2 in Arquivos2)
{
label8.Text = "Enviando(NFe): " + fileinfo2.Name + "...";
label8.Update();
WebClient client = new WebClient();
client.Credentials = new System.Net.NetworkCredential(usuario, senha);
client.UploadProgressChanged += new UploadProgressChangedEventHandler(UploadProgressCallback);
client.UploadFile(new Uri("ftp://" + ftp + "/" + caminho + "//nf//" + fileinfo2.Name), "STOR", #"C:\\NFe\" + fileinfo2.Name);
bar++;
backgroundWorker1.ReportProgress(bar);
}
Its work fine, but I have:
private void UploadProgressCallback(object sender, UploadProgressChangedEventArgs e)
{
progressBar2.Value = e.ProgressPercentage;
progressBar2.Update();
}
and nothing happens with progressBar2...
How I can update my progressBar2 with a uploadprogress? I can't use UploadFile with UploadProgressChanged?

According to http://msdn.microsoft.com/en-us/library/system.net.webclient.uploadprogresschanged.aspx
This event is raised each time an asynchronous upload makes progress.
It is only raised by 3 asynchronous events. The version you are calling is a blocking method and does not return until it completes and does not raise progress events.

Related

Pause loop until download event is complete

How can I pause the loop in someRandomMethod() until the code in DownloadCompleted() have been executed? This code below only unpacks the latest version in the versions array. It's like the loop is faster than the first download and m_CurrentlyDownloading have the latest value the first time DownloadCompleted() is beeing executed.
private void someRandomMethod() {
for (int i = 0; i < versions.Count; i++)
{
//ClearInstallFolder();
m_CurrentlyDownloading = versions.ElementAt(i);
Download(versions.ElementAt(i));
LocalUpdate(versions.ElementAt(i));
System.Threading.Thread.Sleep(500);
}
}
private void Download(string p_Version)
{
string file = p_Version + ".zip";
string url = #"http://192.168.56.5/" + file;
//client is global in the class
client = new WebClient();
client.DownloadFileCompleted += new AsyncCompletedEventHandler(DownloadCompleted);
client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(DownloadProgressChanged);
client.DownloadFileAsync(new Uri(url), #"C:\tmp\" + file);
}
private void DownloadCompleted(object sender, AsyncCompletedEventArgs e)
{
if (e.Error == null)
{
Unpack(m_CurrentlyDownloading);
if (GetInstalledVersion() == GetLatestVersion())
ClearZipFiles();
}
else
MessageBox.Show(e.Error.ToString());
}
The easiest way would be to not use the *async methods. The normal DownloadFile will pause execution until it completes.
But if you've got access to the Await keyword, try this.
private async Task Download(string p_Version)
{
string file = p_Version + ".zip";
string url = #"http://192.168.56.5/" + file;
//client is global in the class
client = new WebClient();
client.DownloadFileCompleted += new AsyncCompletedEventHandler(DownloadCompleted);
client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(DownloadProgressChanged);
await client.DownloadFileAsync(new Uri(url), #"C:\tmp\" + file);
}
something like this can be used to wait
make it class property
bool IsDownloadCompleted=false;
Add this in DownloadCompletedEvent
IsDownloadCompleted=true;
and this where you want to stop loop
while(DownloadCompleted!=true)
{
Application.DoEvents();
}
Create some boolean variable, create a delegate and get\set methods for this variable.
Then just in loop made smth like :
while(!isDownLoadCompleted)Thread.Sleep(1024);
You Can use Paralel.ForEach. this loop will wait until all threads done.
check Here for how to use :
http://msdn.microsoft.com/tr-tr/library/dd460720(v=vs.110).aspx
or
http://blogs.msdn.com/b/pfxteam/archive/2012/03/05/10278165.aspx

Download multiple files in C# (one at a time only / queue)

I'm writing an updater in C# and I need some help now (I'm new to this language, please explain your tips :D )
My Code:
System.IO.Directory.CreateDirectory("tmp");
int mmx = updnec.Count();
label6.Text = "0/" + mmx;
MessageBox.Show(label6.Text);
int mmn = 0;
foreach (string lz in link)
{
MessageBox.Show(lz);
client.DownloadFileAsync(new Uri(lz), "tmp/update00" + mmn + ".exe");
client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
label6.Text = mmn + "/" + mmx;
mmn = +1;
//Whithout that while{} - part, it tries to download all links from the list at once. But I don't want the program to do that. I don't want it to show a message all the time, too, but when i leave that while{} - part empty, the program just freezes and doesn't even download.
while (progressBar1.Maximum != progressBar1.Value)
{
MessageBox.Show("Test");
}
}
}
void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
progressBar1.Maximum = (int)e.TotalBytesToReceive;
progressBar1.Value = (int)e.BytesReceived;
string sysload = progressBar1.Value /1000000 + "/" + progressBar1.Maximum /1000000 + " MB geladen";
label12.Text = sysload;
}
Read the comment int my code please.
How to solve my problem!? Please help me!
Reditec
Edit:
label11.Text = System.DateTime.Now.ToString();
backgroundWorker1.RunWorkerAsync(link);
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
List<string> lz = (List<string>)e.Argument;
int mmn = 0;
progressBar1.Style = ProgressBarStyle.Blocks;
System.IO.Directory.CreateDirectory("tmp");
int mmx = 10;
label6.Text = "0/" + mmx;
foreach (string lkz in lz)
using (var client = new WebClient())
{
MessageBox.Show("Hallo" + lkz);
client.DownloadFile(lkz, "tmp/update00" + mmn + ".exe");
}
}
Try use a BackgroundWorker and download your files in sync instead of async.
You can find an example here:
http://www.codeproject.com/Tips/83317/BackgroundWorker-and-ProgressBar-demo
Here is an example:
void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
var links = new[] { "link1", "link2" };
var percentProgressStep = (100 / links.Length) + 1
using (var client = new WebClient())
foreach (string l in links)
{
client.DownloadFile(l, Path.GetTempFileName());
backgroundWorker1.ReportProgress(percentProgressStep);
}
}

UploadFileAsync with Foreach

I have:
foreach (FileInfo fileinfo in Arquivos)
{
float zz = (float)fileinfo.Length;
zz = (zz / 1024f) / 1024f;
label8.Text = "sending: " + fileinfo.Name + "("+zz.ToString("0.0")+"MB)...";
label8.Update();
WebClient client = new System.Net.WebClient();
client.Credentials = new System.Net.NetworkCredential(usuario, senha);
client.UploadProgressChanged += new UploadProgressChangedEventHandler(UploadProgressCallback);
client.UploadFile(new Uri("ftp://" + ftp + "/" + caminho + "//" + fileinfo.Name), "STOR", pasta + mes + fileinfo.Name);
bar++;
backgroundWorker1.ReportProgress(bar);
}
And I need create a UploadProgressChanged, so I have:
client.UploadProgressChanged += new UploadProgressChangedEventHandler(UploadProgressCallback);
And
private void UploadProgressCallback(object sender, UploadProgressChangedEventArgs e)
{
progressBar2.Value = e.ProgressPercentage;
progressBar2.Update();
}
UploadProgressChanged not work with UploadFile, just UploadfileAsync, but I need send 1 file per time. How can I change UploadFile to UploadFileAsync and send a file per time?
If you're only able to send 1 file at a time then why are you concerned about using Async? You also seem to be using a background worker to do all the work.
Might you not be better off spinning up a 'Task' for each file to be uploaded, and kicking them off with a scheduler that only allows one task at a time?
see: http://msdn.microsoft.com/en-us/library/ee789351.aspx
That way you could make use of some the newer Task and async methods available while simplifying your task.
Based on further analysis if you want to run them asynchronously but only do one at a time:
private AutoResetEvent _fileUploadedEvent = new AutoResetEvent(false);
private void DoUploadBackgroundWorker()
{
foreach (var file in files)
{
client.WhenUploaded += (s, e) =>
{
// This signals the AutoResetEvent that it can continue
_fileUploadedEvent.Set();
};
client.UploadAsync();
// This will keep ticking over every 15 milliseconds to check if the
// AutoResetEvent has been triggered
while (_fileUploadedEvent.WaitOne(15)) { }
// We get here when it's been triggered (which means the file was uploaded)
// So we can update the progressbar here and then move onto the next file.
}
}
It needs expanding and the classes aren't all correct as I've just knocked this together, but it should provide enough material to start you in the direction.

WebClient does not support concurrent I/O operations

I did what #Enigmativity write
here it is:
Action<int, ProgressBar, Label, Label, int, Button> downloadFileAsync = (i, pb, label2, label1, ServID, button1) =>
{
var bd = AppDomain.CurrentDomain.BaseDirectory;
var fn = bd + "/" + i + ".7z";
var down = new WebClient();
DownloadProgressChangedEventHandler dpc = (s, e) =>
{
label1.Text = "Download Update: " + i + " From: " + ServID;
int rec =Convert.ToInt16(e.BytesReceived / 1024);
int total =Convert.ToInt16(e.TotalBytesToReceive / 1024) ;
label2.Text = "Downloaded: " + rec.ToString() + " / " + total.ToString() + " KB";
pb.Value = e.ProgressPercentage;
};
AsyncCompletedEventHandler dfc = null; dfc = (s, e) =>
{
down.DownloadProgressChanged -= dpc;
down.DownloadFileCompleted -= dfc;
CompressionEngine.Current.Decoder.DecodeIntoDirectory(AppDomain.CurrentDomain.BaseDirectory + "/" + i + ".7z", AppDomain.CurrentDomain.BaseDirectory);
File.Delete(fn);
if (i == ServID)
{
button1.Enabled = true;
label1.Text = "Game Is Up-To-Date.Have Fun!!";
label2.Text = "Done..";
}
down.Dispose();
};
My only problam now is when the program is extarting the downloaded file
CompressionEngine.Current.Decoder.DecodeIntoDirectory(AppDomain.CurrentDomain.BaseDirectory + "/" + i + ".7z", AppDomain.CurrentDomain.BaseDirectory);
In some files its take time to extarct the downloaded file
so how i can tell the program to wait until decompressing is complete?
Try defining a single lambda that will encapsulate a single async download and then call that in a loop.
Here's the lambda:
Action<int> downloadFileAsync = i =>
{
var bd = AppDomain.CurrentDomain.BaseDirectory;
var fn = bd + "/" + i + ".7z";
var wc = new WebClient();
DownloadProgressChangedEventHandler dpc = (s, e) =>
{
progressBar1.Value = e.ProgressPercentage;
};
AsyncCompletedEventHandler dfc = null;
dfc = (s, e) =>
{
wc.DownloadProgressChanged -= dpc;
wc.DownloadFileCompleted -= dfc;
CompressionEngine.Current.Decoder.DecodeIntoDirectory(fn, bd);
File.Delete(fn);
wc.Dispose();
};
wc.DownloadProgressChanged += dpc;
wc.DownloadFileCompleted += dfc;
wc.DownloadFileAsync(new Uri(Dlpath + i + "/" + i + ".7z"), fn);
};
You'll note that it nicely detaches all events and also correctly disposes of the WebClient instance.
Now call it like this:
while (i <= ServID)
{
downloadFileAsync(i);
i++;
}
You'll have to fiddle with the progress bar update to properly show the progress of all the files downloading, but in principle this should work for you.

How to access additional classes in events

I'm trying to access the Script class that is in the code block below in the event triggered when a file download is completed. How would I be able to do that?
public void DownloadScript(Script script, string DownloadLocation)
{
AddLog(GenerateLog("Downloading Script", "Started", "Downloading " + script.Name + " from " + script.DownloadURL + "."));
WebClient Client = new WebClient();
Client.DownloadFileCompleted += new System.ComponentModel.AsyncCompletedEventHandler(Client_DownloadFileCompleted);
Client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(Client_DownloadProgressChanged);
Client.DownloadFileAsync(new Uri(script.DownloadURL), DownloadLocation + "test1.zip");
}
Here is the event that is triggered.
public void Client_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
if (e.Error.Message != string.Empty)
{
AddLog(GenerateLog("Downloading Script", "Error", "There was an error downloading " + script.Name + " from " + script.DownloadURL + ". " + e.Error.Message));
Console.WriteLine("Error");
}
else
{
AddLog(GenerateLog("Downloading Script", "Done", "Finished downloading " + script.Name + " from " + script.DownloadURL + "."));
Console.WriteLine("Done");
}
}
You can use a lambda expression to capture the Script object and pass it along to the handler as an extra parameter.
public void DownloadScript(Script script, string DownloadLocation) {
...
WebClient Client = new WebClient();
Client.DownloadFileCompleted += (sender, e) => Client_DownloadFileCompleted(
sender,
e,
script);
}
public void Client_DownloadFileCompleted(
object sender,
AsyncCompletedEventArgs e,
Script script) {
...
}

Categories

Resources