So basically my DownloadFile is:
public void DownloadFile()
{
settings_btn.Enabled = false;
label1.Text = "Checking for updates...";
//Defines the server's update directory
string Server = "http://downloadurl/update/";
//Defines application root
string Root = AppDomain.CurrentDomain.BaseDirectory;
//Make sure version file exists
FileStream fs = null;
if (!File.Exists("pversion"))
{
using (fs = File.Create("pversion")){}
using (StreamWriter sw = new StreamWriter("pversion")){sw.Write("1.0");}
}
//checks client version
string lclVersion;
using (StreamReader reader = new StreamReader("pversion"))
{
lclVersion = reader.ReadLine();
}
decimal localVersion = decimal.Parse(lclVersion);
//server's list of updates
XDocument serverXml = XDocument.Load(#Server + "pUpdates.xml");
//The Update Process
foreach (XElement update in serverXml.Descendants("pupdate"))
{
string version = update.Element("pversion").Value;
string file = update.Element("pfile").Value;
decimal serverVersion = decimal.Parse(version);
string sUrlToReadFileFrom = Server + file;
string sFilePathToWriteFileTo = Root + file;
if (serverVersion > localVersion)
{
using (webClient = new WebClient())
{
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(Completed);
webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(ProgressChanged);
// The variable that will be holding the url address (making sure it starts with http://)
Uri url = new Uri(sUrlToReadFileFrom);
// Start the stopwatch which we will be using to calculate the download speed
sw.Start();
try
{
// Start downloading the file
webClient.DownloadFileAsync(url, sFilePathToWriteFileTo);
// Change the currently running executable so it can be overwritten.
Process thisprocess = Process.GetCurrentProcess();
string me = thisprocess.MainModule.FileName;
string bak = me + ".bak";
if (File.Exists(bak))
{
File.Delete(bak);
}
File.Move(me, bak);
File.Copy(bak, me);
//unzip
using (ZipFile zip = ZipFile.Read(file))
{
foreach (ZipEntry zipFiles in zip)
{
zipFiles.Extract(Root + "\\", true);
}
}
//download new version file
webClient.DownloadFile(Server + "pversion.txt", #Root + "pversion");
//Delete Zip File
deleteFile(file);
var spawn = Process.Start(me);
thisprocess.CloseMainWindow();
thisprocess.Close();
thisprocess.Dispose();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
}
}
And my problem is that once it finds a new version and starts downloading the file webClient.DownloadFileAsync(url, sFilePathToWriteFileTo);, it instantly runs the code below which is the changing name, unzipping and downloading new version file progress
What I want it to do is wait for it to finish downloading the file, and THEN do the rest. How do I do this?
-- In case this is necessary, ProgressChanged:
private void ProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
label3.Text = string.Format("{0} kb/s", (e.BytesReceived / 1024d / sw.Elapsed.TotalSeconds).ToString("0.00")) + " " + string.Format("{0} MB's / {1} MB's", (e.BytesReceived / 1024d / 1024d).ToString("0.00"), (e.TotalBytesToReceive / 1024d / 1024d).ToString("0.00"));;
progressBar1.Value = e.ProgressPercentage;
label1.Text = e.ProgressPercentage.ToString() + "%";
}
and Completed:
private void Completed(object sender, AsyncCompletedEventArgs e)
{
sw.Reset();
if (e.Cancelled == true)
{
label1.Text = "Download cancelled!";
}
else
{
label1.Text = "Download completed!";
}
}
You can use the DownloadFile method. The Async word means that this method will run asynchronous (in other thread), that's why it's goes to next line praticaly instantly.
If you want wait for download ends, use the DownloadFile instead of DownloadFileAsync
Related
then after the first file it's downloading all the rest of the files in the links fast but the first one take a lot of time.
the button click event to start the downloading.
private async void btnStart_Click(object sender, EventArgs e)
{
CreateDownloadFolders createDownloadFolders = new CreateDownloadFolders();
createDownloadFolders.GenerateDownloadFolders(textBoxRadarPath.Text, textBoxSatellitePath.Text);
lblStatus.Text = "Preparing Downloads";
loadingLabel1.Visible = true;
radar.PrepareLinks();
await satellite.DownloadSatelliteAsync();
downloadLinks.AddRange(radar.links);
downloadLinks.AddRange(satellite.links);
loadingLabel1.Visible = false;
for (int i = 0; i < downloadLinks.Count; i++)
{
if (downloadLinks[i].Contains("Radar"))
{
lblStatus.Text = "Downloading radar images";
await DownloadFiles(downloadLinks[i], Path.Combine(textBoxRadarPath.Text,
$"RadarImage{countRadarImages + 1}.gif"));
countRadarImages++;
}
else
{
lblStatus.Text = "Downloading satellite images";
await DownloadFiles(downloadLinks[i], Path.Combine(textBoxSatellitePath.Text,
$"SatelliteImage{countSatelliteImages + 1}.gif"));
countSatelliteImages++;
}
}
}
i used a break point and it's getting very fast to the for loop :
for (int i = 0; i < downloadLinks.Count; i++)
then i added another break point in the DownloadFiles method : and it's getting fast to the line :
await webClient.DownloadFileTaskAsync(URL, location);
this is the DownloadFiles method
public async Task DownloadFiles(string urlAddress, string location)
{
Stopwatch sw = new Stopwatch();
using (WebClient webClient = new WebClient())
{
webClient.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:67.0) Gecko/20100101 Firefox/67.0 Chrome");
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(((sender, e) => Completed(sender, e, sw)));
webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler((sender, e) => ProgressChanged(sender, e, sw));
Uri URL = new Uri(urlAddress);
sw.Start();
try
{
savedFile = location;
await webClient.DownloadFileTaskAsync(URL, location);
}
catch (Exception ex)
{
string err = ex.Message;
}
}
}
but then it's not getting to the progress changed event and the completed event
private void ProgressChanged(object sender, DownloadProgressChangedEventArgs e, Stopwatch sw)
{
string downloadProgress = e.ProgressPercentage + "%";
string downloadSpeed = string.Format("{0} MB/s", (e.BytesReceived / 1024.0 / 1024.0 / sw.Elapsed.TotalSeconds).ToString("0.00"));
string downloadedMBs = Math.Round(e.BytesReceived / 1024.0 / 1024.0) + " MB";
string totalMBs = Math.Round(e.TotalBytesToReceive / 1024.0 / 1024.0) + " MB";
// Format progress string
string progress = $"{downloadedMBs}/{totalMBs} ({downloadProgress}) # {downloadSpeed}"; // 10 MB / 100 MB (10%) # 1.23 MB/s
textProgressBar1.Value = e.ProgressPercentage;
textProgressBar1.CustomText = progress;
}
private void Completed(object sender, AsyncCompletedEventArgs e, Stopwatch sw)
{
if (e.Cancelled == true)
{
sw.Stop();
}
if (e.Error != null)
{
filesCounter--;
File.Delete(savedFile);
if(filesCounter == 0)
{
lblStatus.Text = "Downloading Finished";
}
}
else
{
filesCounter--;
sw.Stop();
if (radar.links.Count == 0)
{
sw.Stop();
}
}
}
after the line
await webClient.DownloadFileTaskAsync(URL, location);
it's just hanging not freezing the application just hanging for almost 30 seconds and then start downloading the rest of the files very fast.
why at the first time it's hanging/waiting so much time and not downloading all the files?
I want to show the progress of a downloading process on my ProgressBar. I tried to do somethings like this code for upload, but I failed. Here is an example of my failed attempts
private void button5_Click(object sender, EventArgs e)
{
Task.Run(() => Download());
}
private void Download()
{
try
{
int Port = (int)numericUpDown1.Value;
string Host = comboBox1.Text;
string Username = textBox3.Text;
string Password = textBox4.Text;
string SourcePath = textBox5.Text;
string RemotePath = textBox6.Text;
string FileName = textBox7.Text;
using (var file = File.OpenWrite(SourcePath + FileName))
using (var Stream = new FileStream(SourcePath + FileName, FileMode.Open))
using (var Client = new SftpClient(Host, Port, Username, Password))
{
Client.Connect();
progressBar1.Invoke((MethodInvoker)
delegate
{
progressBar1.Maximum = (int)Stream.Length;
});
Client.DownloadFile(RemotePath + FileName, /*file*/ Stream, DownloadProgresBar);
Client.Disconnect();
}
}
catch (Exception Ex)
{
System.Windows.Forms.MessageBox.Show(Ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void DownloadProgresBar(ulong Downloaded)
{
progressBar1.Invoke((MethodInvoker)
delegate
{
progressBar1.Value = (int)Downloaded;
});
}
Thank you in advance
As you correctly did, similarly to the code for displaying progress of file upload, you have to provide a callback to the downloadCallback argument of SftpClient.DownloadFile.
public void DownloadFile(
string path, Stream output, Action<ulong> downloadCallback = null)
Also you correctly download on a background thread. Alternatively, you could use an asynchronous upload (SftpClient.BeginDownloadFile).
What is wrong and needs change:
You have to open/create the local file for writing (FileMode.Create).
You have to retrieve a size of the remote file, not the local one (not existing yet). Use SftpClient.GetAttributes.
Example using a background thread (task):
private void button1_Click(object sender, EventArgs e)
{
// Run Download on background thread
Task.Run(() => Download());
}
private void Download()
{
try
{
int Port = 22;
string Host = "example.com";
string Username = "username";
string Password = "password";
string RemotePath = "/remote/path/";
string SourcePath = #"C:\local\path\";
string FileName = "download.txt";
string SourceFilePath = SourcePath + FileName;
using (var stream = new FileStream(SourceFilePath, FileMode.Create))
using (var client = new SftpClient(Host, Port, Username, Password))
{
client.Connect();
string RemoteFilePath = RemotePath + FileName;
SftpFileAttributes attrs = client.GetAttributes(RemoteFilePath);
// Set progress bar maximum on foreground thread
int max = (int)attrs.Size;
progressBar1.Invoke(
(MethodInvoker)delegate { progressBar1.Maximum = max; });
// Download with progress callback
client.DownloadFile(RemoteFilePath, stream, DownloadProgresBar);
MessageBox.Show("Download complete");
}
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}
private void DownloadProgresBar(ulong uploaded)
{
// Update progress bar on foreground thread
progressBar1.Invoke(
(MethodInvoker)delegate { progressBar1.Value = (int)uploaded; });
}
For upload see:
Displaying progress of file upload in a ProgressBar with SSH.NET
I've created a little launcher program with my "Updater" code to download a file that has a version number. The updater tests that version number against a file that ships with the installer. If greater, download a .msi and execute. The problem is that on a Server 2012 machine the version file to be downloaded is empty upon arrival, while on a Server 2012 R2, the downloaded version is populated and correct. The same goes for my Dad's 8.1 machine. See code. Obviously, I don't own blah.com either.
using System;
using System.ComponentModel;
using System.Windows.Forms;
using System.IO;
using System.Net;
using System.Diagnostics;
using System.Reflection;
namespace ra2kui
{
public partial class Updater : Form
{
Stopwatch sw = new Stopwatch();
string temppath = Path.GetTempPath();
public Updater()
{
InitializeComponent();
labelAssemblyVersion.Text = String.Format("Assembly Version: {0}", AssemblyVersion);
}
public string AssemblyVersion
{
get
{
return Assembly.GetExecutingAssembly().GetName().Version.ToString();
}
}
private void MainPage_Load(object sender, EventArgs e)
{
string currentver;
if (File.Exists(#"lib\\vo.r2k"))
{
using (StreamReader currentverreader = new StreamReader("lib\\vo.r2k"))
{
currentver = currentverreader.ReadLine() ?? "";
}
labelCurrentVersion.Text = "Current Package Version: " + currentver;
}
else
{
MessageBox.Show("VO missing.");
return;
}
buttonMulti.Text = "Downloading Version File From Server...";
labelVersionOnServer.Text = "Server Package Version: ";
if (File.Exists(temppath + #"2kuv.r2k"))
{
File.Delete(temppath + #"2kuv.r2k");
}
Application.DoEvents();
// Download the version from the server...
WebClient webClient = new WebClient();
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(Completed);
webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(ProgressChanged);
// Start the stopwatch
//Stopwatch sw = new Stopwatch();
sw.Start();
try
{
webClient.DownloadFileAsync(new Uri("https://www.blah.com/package/2kuv.r2k"), temppath + #"2kuv.r2k");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void ProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
// Progress bar value change
progressBar1.Value = e.ProgressPercentage;
// Calculate download speed and output it to labelSpeed.
labelSpeed.Text = string.Format("{0} kB/s", (e.BytesReceived / 1024d / sw.Elapsed.TotalSeconds).ToString("0"));
// Show the percentage on our label.
labelPerc.Text = e.ProgressPercentage.ToString() + "%";
// Update the label with how much data have been downloaded so far and the total size of the file we are currently downloading
labelDownloaded.Text = string.Format("{0} MB's / {1} MB's",
(e.BytesReceived / 1024d / 1024d).ToString("0.00"),
(e.TotalBytesToReceive / 1024d / 1024d).ToString("0.00"));
}
private void Completed(object sender, AsyncCompletedEventArgs e)
{
string updatever;
string origver;
using (StreamReader updatereader = new StreamReader(temppath + "2kuv.r2k"))
{
updatever = updatereader.ReadLine() ?? "";
}
using (StreamReader origreader = new StreamReader("lib\\vo.r2k"))
{
origver = origreader.ReadLine() ?? "";
}
if (String.Compare(origver,updatever) > 0)
{
MessageBox.Show("There is no update available. Or there was an issue with the UV file.");
this.Close();
}
else if(String.Compare(origver,updatever) < 0)
{
MessageBox.Show("There is an update available.");
labelVersionOnServer.Text = "Server Package Version: " + updatever;
buttonMulti.Text = "Download and proceed with update...";
buttonMulti.Enabled = true;
}
else if(String.Compare(origver,updatever) == 0)
{
MessageBox.Show("You are on the most current version.");
this.Close();
}
}
private void buttonMulti_Click(object sender, EventArgs e)
{
buttonMulti.Text = "Downloading update...";
buttonMulti.Enabled = false;
Application.DoEvents();
//Create Stopwatch
sw.Start();
WebClient webClient = new WebClient();
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(Completed2);
webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(ProgressChanged);
try
{
webClient.DownloadFileAsync(new Uri("https://www.blah.com/package/setup32.msi"), temppath + #"setup32.msi");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void Completed2(object sender, AsyncCompletedEventArgs e)
{
MessageBox.Show("The updater will now close and start the update.");
try
{
Process.Start(temppath + "setup32.msi");
Application.Exit();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
Application.Exit();
}
}
}
}
I have this code:
int countfiletodownload = 0;
bool processStatus = false;
private void Parseanddownloadfiles()
{
downloadhtml(mainurl);
if (bgw.CancellationPending == false)
{
backgroundWorker1.ReportProgress(0, "Parsing Links");
HtmlAgilityPack.HtmlWeb hw = new HtmlAgilityPack.HtmlWeb();
HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
doc = hw.Load(path_exe + "\\page.html");
foreach (HtmlAgilityPack.HtmlNode link in doc.DocumentNode.SelectNodes("//a[#href]"))
{
string hrefValue = link.GetAttributeValue("href", string.Empty);
if (hrefValue.Contains("US"))
{
string url = "http://www.mytests.com;
parsedlinks.Add(url);
if (bgw.CancellationPending == true)
return;
}
}
countfiletodownload = parsedlinks.Count;
backgroundWorker1.ReportProgress(0, "Downloading Files");
processStatus = true;
for (int i = 0; i < parsedlinks.Count && bgw.CancellationPending == false; i++)
{
try
{
using (WebClient client = new WebClient())
{
client.DownloadFileCompleted += client_DownloadFileCompleted;
client.DownloadProgressChanged += client_DownloadProgressChanged;
sw.Start();
Uri uri = new Uri(parsedlinks[i]);
string filename = parsedlinks[i].Substring(71);
client.DownloadFileAsync(uri, filesdirectory + "\\" + filename);
string filenametoreport = filename.Substring(1);
countfiletodownload--;
backgroundWorker1.ReportProgress(countfiletodownload, filenametoreport);
}
}
catch (Exception err)
{
string error = err.ToString();
}
}
}
}
void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
// Calculate download speed and output it to labelSpeed.
label12.Text = string.Format("{0} kb/s", (e.BytesReceived / 1024d / sw.Elapsed.TotalSeconds).ToString("0.00"));
// Update the progressbar percentage only when the value is not the same.
progressBar1.Value = e.ProgressPercentage;
// Show the percentage on our label.
label13.Text = e.ProgressPercentage.ToString() + "%";
// Update the label with how much data have been downloaded so far and the total size of the file we are currently downloading
label14.Text = string.Format("{0} MB's / {1} MB's",
(e.BytesReceived / 1024d / 1024d).ToString("0.00"),
(e.TotalBytesToReceive / 1024d / 1024d).ToString("0.00"));
}
void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
// Reset the stopwatch.
sw.Reset();
if (e.Cancelled == true)
{
MessageBox.Show("Download has been canceled.");
}
else
{
MessageBox.Show("Download completed!");
}
}
I'm registering two events of the WebClient,
DownloadFileCompleted and DownloadProgressChanged.
The method Parseanddownloadfiles() is being called from the backgroundworker dowork event:
BackgroundWorker bgw;
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
bgw = (BackgroundWorker)sender;
if (bgw.CancellationPending == true)
{
return;
}
else
{
Parseanddownloadfiles();
}
}
Once I added the client two events, I was getting an exception in the client_DownloadProgressChanged event on the first line:
label12.Text = string.Format("{0} kb/s", (e.BytesReceived / 1024d / sw.Elapsed.TotalSeconds).ToString("0.00"));
Cross-thread operation not valid: Control 'label12' accessed from a thread other than the thread it was created on
How should I work around this exception?
To make cross-thread calls to a UI element you can setup and use an invoke delegate. This example is only for the one label. All other controls would have to have a similar method.
//Create a delegate for the call
public delegate void VoidStringDelegate(string str);
public void UpdateLabel12(string LabelText)
{
if (!label12.InvokeRequired)
{//If on the same thread directly change the value
label12.Text = LabelText;
}
else
{//If on a separate thread make an invoke call to this method from the correct thread
label12.Invoke(new VoidStringDelegate(UpdateLabel12), LabelText);
}
}
Change the "problematic" line to:
label12.BeginInvoke((Action)(() => label12.Text = string.Format("{0} kb/s", (e.BytesReceived / 1024d / sw.Elapsed.TotalSeconds).ToString("0.00")));
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.
// 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