[英]How to implement a Timeout on WebClient.DownloadFileAsync
So I thought Webclient.DownloadFileAysnc
would have a default timeout but looking around the documentation I cannot find anything about it anywhere so I'm guessing it doesn't. 因此,我认为Webclient.DownloadFileAysnc
将具有默认超时时间,但是在文档中查找时,我在任何地方都找不到任何内容,因此我猜没有找到任何内容。
I am trying to download a file from the internet like so: 我试图像这样从互联网下载文件:
using (WebClient wc = new WebClient())
{
wc.DownloadProgressChanged += ((sender, args) =>
{
IndividualProgress = args.ProgressPercentage;
});
wc.DownloadFileCompleted += ((sender, args) =>
{
if (args.Error == null)
{
if (!args.Cancelled)
{
File.Move(filePath, Path.ChangeExtension(filePath, ".jpg"));
}
mr.Set();
}
else
{
ex = args.Error;
mr.Set();
}
});
wc.DownloadFileAsync(new Uri("MyInternetFile", filePath);
mr.WaitOne();
if (ex != null)
{
throw ex;
}
}
But if I turn off my WiFi (simulating a drop of internet connection) my application just pauses and the download stops but it will never report that through to the DownloadFileCompleted
method. 但是,如果我关闭WiFi(模拟断开互联网连接),则我的应用程序只会暂停并且下载会停止,但它永远不会报告给DownloadFileCompleted
方法。
For this reason I would like to implement a timeout on my WebClient.DownloadFileAsync
method. 因此,我想在WebClient.DownloadFileAsync
方法上实现超时。 Is this possible? 这可能吗?
As an aside I am using .Net 4 and don't want to add references to third party libraries so cannot use the Async/Await
keywords 顺便说一句,我正在使用.Net 4,并且不想添加对第三方库的引用,因此不能使用Async/Await
关键字
You can use WebClient.DownloadFileAsync(). 您可以使用WebClient.DownloadFileAsync()。 Now inside a timer you can call CancelAsync() like so: 现在,在计时器内部,您可以像这样调用CancelAsync():
System.Timers.Timer aTimer = new System.Timers.Timer();
System.Timers.ElapsedEventHandler handler = null;
handler = ((sender, args)
=>
{
aTimer.Elapsed -= handler;
wc.CancelAsync();
});
aTimer.Elapsed += handler;
aTimer.Interval = 100000;
aTimer.Enabled = true;
Else create your own weclient 否则创建您自己的weclient
public class NewWebClient : WebClient
{
protected override WebRequest GetWebRequest(Uri address)
{
var req = base.GetWebRequest(address);
req.Timeout = 18000;
return req;
}
}
Create a WebClientAsync class that implements the timer in the constructor. 创建一个WebClientAsync类,该类在构造函数中实现计时器。 This way you aren't copying and pasting the timer code into every implementation. 这样,您无需将计时器代码复制并粘贴到每个实现中。
public class WebClientAsync : WebClient
{
private int _timeoutMilliseconds;
public EdmapWebClientAsync(int timeoutSeconds)
{
_timeoutMilliseconds = timeoutSeconds * 1000;
Timer timer = new Timer(_timeoutMilliseconds);
ElapsedEventHandler handler = null;
handler = ((sender, args) =>
{
timer.Elapsed -= handler;
this.CancelAsync();
});
timer.Elapsed += handler;
timer.Enabled = true;
}
protected override WebRequest GetWebRequest(Uri address)
{
WebRequest request = base.GetWebRequest(address);
request.Timeout = _timeoutMilliseconds;
((HttpWebRequest)request).ReadWriteTimeout = _timeoutMilliseconds;
return request;
}
protected override voidOnDownloadProgressChanged(DownloadProgressChangedEventArgs e)
{
base.OnDownloadProgressChanged(e);
timer.Reset(); //If this does not work try below
timer.Start();
}
}
This will allow you to timeout if you lose Internet connection while downloading a file. 如果在下载文件时失去Internet连接,这将使您超时。
Here is another implementation, I tried to avoid any shared class/object variables to avoid trouble with multiple calls: 这是另一种实现,我试图避免任何共享的类/对象变量,以避免多次调用带来麻烦:
public Task<string> DownloadFile(Uri url)
{
var tcs = new TaskCompletionSource<string>();
Task.Run(async () =>
{
bool hasProgresChanged = false;
var timer = new Timer(new TimeSpan(0, 0, 20).TotalMilliseconds);
var client = new WebClient();
void downloadHandler(object s, DownloadProgressChangedEventArgs e) => hasProgresChanged = true;
void timerHandler(object s, ElapsedEventArgs e)
{
timer.Stop();
if (hasProgresChanged)
{
timer.Start();
hasProgresChanged = false;
}
else
{
CleanResources();
tcs.TrySetException(new TimeoutException("Download timedout"));
}
}
void CleanResources()
{
client.DownloadProgressChanged -= downloadHandler;
client.Dispose();
timer.Elapsed -= timerHandler;
timer.Dispose();
}
string filePath = Path.Combine(Path.GetTempPath(), Path.GetFileName(url.ToString()));
try
{
client.DownloadProgressChanged += downloadHandler;
timer.Elapsed += timerHandler;
timer.Start();
await client.DownloadFileTaskAsync(url, filePath);
}
catch (Exception e)
{
tcs.TrySetException(e);
}
finally
{
CleanResources();
}
return tcs.TrySetResult(filePath);
});
return tcs.Task;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.