C# 如何在WebClient.DownloadFileAsync上实现超时
所以我想,C# 如何在WebClient.DownloadFileAsync上实现超时,c#,.net-4.0,timeout,webclient,C#,.net 4.0,Timeout,Webclient,所以我想,Webclient.DownloadFileAysnc会有一个默认超时,但是查看文档时,我在任何地方都找不到关于它的任何信息,所以我猜不会 我正在尝试从internet下载一个文件,如下所示: using (WebClient wc = new WebClient()) { wc.DownloadProgressChanged += ((sender, args) => { IndividualProgress = args.P
Webclient.DownloadFileAysnc
会有一个默认超时,但是查看文档时,我在任何地方都找不到关于它的任何信息,所以我猜不会
我正在尝试从internet下载一个文件,如下所示:
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;
}
}
但如果我关闭WiFi(模拟互联网连接中断),我的应用程序就会暂停,下载也会停止,但它永远不会通过DownloadFileCompleted
方法报告
因此,我想在我的WebClient.DownloadFileAsync
方法上实现一个超时。这可能吗
另外,我使用的是.Net 4,不想添加对第三方库的引用,因此无法使用
Async/Await
关键字您可以使用WebClient.DownloadFileAsync()。现在,在计时器中,您可以调用CancelAsync(),如下所示:
否则创建您自己的weclient
public class NewWebClient : WebClient
{
protected override WebRequest GetWebRequest(Uri address)
{
var req = base.GetWebRequest(address);
req.Timeout = 18000;
return req;
}
}
创建在构造函数中实现计时器的WebClientAsync类。这样,您就不会将计时器代码复制和粘贴到每个实现中
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();
}
}
这将允许您在下载文件时丢失Internet连接时超时。这里是另一个实现,我尝试避免任何共享类/对象变量,以避免多次调用时出现问题:
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;
}
公共任务下载文件(Uri url)
{
var tcs=new TaskCompletionSource();
Task.Run(异步()=>
{
bool hasProgresChanged=false;
var timer=新计时器(新时间跨度(0,0,20).total毫秒);
var client=new WebClient();
void downloadHandler(对象s,DownloadProgressChangedEventArgs e)=>hasprogreChanged=true;
无效时间句柄(对象s、ElapsedEventArgs e)
{
timer.Stop();
如果(hasProgresChanged)
{
timer.Start();
hasProgresChanged=false;
}
其他的
{
清洁资源();
tcs.TrySetException(新的TimeoutException(“下载timedout”);
}
}
void CleanResources()
{
client.DownloadProgressChanged-=downloadHandler;
client.Dispose();
timer.appeased-=timerHandler;
timer.Dispose();
}
字符串filePath=Path.Combine(Path.GetTempPath(),Path.GetFileName(url.ToString());
尝试
{
client.DownloadProgressChanged+=downloadHandler;
timer.appeased+=timerHandler;
timer.Start();
wait client.DownloadFileTaskAsync(url,文件路径);
}
捕获(例外e)
{
tSystexception(e);
}
最后
{
清洁资源();
}
返回tcs.TrySetResult(文件路径);
});
返回tcs.Task;
}
非常糟糕的方法,计算时间需要额外的线程,而这完全是错误的unncessary@Kilanny你可以自由回答更好的方法。这就是stackoverflow的作用。通过共享学习新知识单独创建自己的webclient无法与async一起工作。您的第一个答案是,使用CancelAsync是我所知道的实现异步web请求超时的唯一方法。谢谢回答得好。下面我将发布一个结合了两者的答案。提供了一种我认为可以更好地完成任务的通用方法。
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;
}