I am using webclient for large size file download.
In my country, every 12 hours, the Ip Changes, so if user is downloading file and his ipChanges , the download hangs, but I get not feedback that it hanged..
I would like to detect this in windows form , c#.
public void DownloadFile(string urlAddress, string location)
{
try
{
// The stopwatch which we will be using to calculate the download speed
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 = urlAddress.StartsWith("http://", StringComparison.OrdinalIgnoreCase) ? new Uri(urlAddress) : new Uri("http://" + urlAddress);
// Start the stopwatch which we will be using to calculate the download speed
sw.Start();
// Start downloading the file
webClient.DownloadFileAsync(new Uri(urlAddress), location);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
I also tried calling this for detecting Ip Address change but it is not being fired when manually resetting router.
public Form1()
{
NetworkChange.NetworkAddressChanged += new NetworkAddressChangedEventHandler(AddressChangedCallback);
}
private void AddressChangedCallback(object sender, EventArgs e)
{
//Code here...
}
Related
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;
}
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"]);
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.
}
}
I try to create a web browser. Currently I try to realize a function that if the user wants to download some file an additional window is shown with a list of already downloaded files. If the file has already been loaded, a message is shown (just an idea).
So far, I get a link to the file location in the main form and send it to the other form:
DownLoadFile dlf = new DownLoadFile();
...
WebBrowser wb = new WebBrowser();
wb.Navigating += new WebBrowserNavigatingEventHandler(wb_Navigating);
...
private void wb_Navigating(object sender, WebBrowserNavigatingEventArgs e)
{
...
if (e.Url.ToString().EndsWith(".mp3"))
{
dlf.DownloadPath = e.Url;
dlf.Show();
}
}
In the new form I try to use this link for file downloading:
public Uri DownloadPath { get; set; }
...
private void DownLoadFile_Load(object sender, EventArgs e)
{
string filePath = null;
//get FileName from URL
string[] ArrayForName;
ArrayForName = DownloadPath.ToString().Split('/');
saveFileDialogFile.FileName =
ArrayForName[ArrayForName.Length-1].Replace("%"," ").Trim();
if (saveFileDialogFile.ShowDialog() == DialogResult.OK)
{
WebClient client = new WebClient();
//get Url
Uri url = new Uri(DownloadPath.ToString());
//get place where want to save with default name
filePath = saveFileDialogFile.FileName;
//event for result
client.DownloadFileCompleted +=
new System.ComponentModel.AsyncCompletedEventHandler (client_DownloadFileCompleted);
//download
client.DownloadFileAsync(url, filePath);
}
}
void client_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
MessageBox.Show("Compleated");
}
My questions are:
Regarding if (e.Url.ToString().EndsWith(".mp3")) - How can i
change this for knowing not only when the user tries to download mp3 file,
but all types of files - maybe there is a better way
If i want to download a file using some link directly, I get the message "Currently you have not required permission for that" - How can I
change permission level for my web browser
If i finally get a link to the file and start to download it, as result just name of file (size of file 0 kb) - where i'm wrong.
my solution (maybe not the best one)
create event for webBrowser
wb.Navigating += new WebBrowserNavigatingEventHandler(wb_Navigating);
and in this event use next
if (GetWorkingWebBrowser().StatusText != null)
{
try
{
WebRequest request = WebRequest.Create(GetWorkingWebBrowser().StatusText);
request.Method = "HEAD";
using (WebResponse response = request.GetResponse())
{
if (response.ContentLength > 0 &&
!response.ContentType.ToString().ToLower().Contains("text/html"))
{
dlf.DownloadPath = e.Url; //move url to my form for dwnload
dlf.Show(); //show form
}
}
}
catch (UriFormatException)
{
}
catch (WebException)
{
}
}
GetWorkingWebBrowser() - method that return current active webBrowser on tab, meas webBrowser
I'm having trouble getting DownloadProgressChangedEventHandler to fire. I understand that, worst case, the event handler should fire every 64Kb. The URL I'm trying to download data from creates 680Kb of XML data on the fly, but the handler does not fire at all.
Here's test code that demonstrates the problem. Unfortunately I cannot share the specific URL as it contains proprietary data.
static void Main(string[] args)
{
Console.WriteLine("Downloading data");
string url = "https://MyUrlThatRespondsWith680KbOfData";
string outputPath = #"C:\Temp\DeleteMe.xml";
using (WebClient webClient = new WebClient())
{
webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(webClient_DownloadProgressChanged);
webClient.DownloadFile(url, outputPath);
}
Console.Write("Done");
Console.ReadKey(true);
}
static void webClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
Console.WriteLine("Download progress: " + e.BytesReceived);
}
Your code looks ok, but documentation says "This event is raised each time an asynchronous download makes progress" while you are using synchronous version of the download. Switch to use DownloadFileAsync.
My code was structured so that the WebClient was already used on a non-UI thread, so I extended WebClient to allow for a synchronous call to get events. I also extended it to allow for a custom connection timeout (I was calling a web service that could take quite a while to respond). The new method DownloadFileWithEvents internally calls DownloadFileAsync and properly blocks until the appropriate complete event is received.
Here's the code in case it's useful to anyone:
public class MyWebClient : WebClient
{
//time in milliseconds
private int timeout;
public int Timeout
{
get
{
return timeout;
}
set
{
timeout = value;
}
}
public MyWebClient(int timeout = 60000)
{
this.timeout = timeout;
this.DownloadFileCompleted += new System.ComponentModel.AsyncCompletedEventHandler(MyWebClient_DownloadFileCompleted);
}
EventWaitHandle asyncWait = new ManualResetEvent(false);
public void DownloadFileWithEvents(string url, string outputPath)
{
asyncWait.Reset();
Uri uri = new Uri(url);
this.DownloadFileAsync(uri, outputPath);
asyncWait.WaitOne();
}
void MyWebClient_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
asyncWait.Set();
}
protected override WebRequest GetWebRequest(Uri address)
{
var result = base.GetWebRequest(address);
result.Timeout = this.timeout;
return result;
}
}