如何处理使用WebClient.DownloadFileAsync时的异常
本文关键字:DownloadFileAsync WebClient 异常 何处理 处理 | 更新日期: 2023-09-27 17:51:16
我正在使用WebClient
以以下方式从互联网下载一些文件:
try
{
ManualResetEvent mr = new ManualResetEvent(false);
mr.Reset();
using (WebClient wc = new WebClient())
{
wc.DownloadFileCompleted += ((sender, args) =>
{
if (args.Error == null)
{
File.Move(filePath, Path.ChangeExtension(filePath, ".jpg"));
mr.Set();
}
else
{
//how to pass args.Error?
}
});
wc.DownloadFileAsync(new Uri(string.Format("{0}/{1}", Settings1.Default.WebPhotosLocation, Path.GetFileName(f.FullName))), filePath);
mr.WaitOne();
}
}
catch (Exception ex)
{
//Catch my error here and handle it (display message box)
}
但是我似乎不能将错误从我的匿名DownloadFileCompleted
方法传递到我的主要捕获。正确的做法是什么?
解决方案不理想
可以将异常保存在lambda之外定义的某个变量中。然后可以重新抛出:
Exception exc = null;
using (WebClient wc = new WebClient())
{
wc.DownloadFileCompleted += ((sender, args) =>
...
mr.WaitOne();
if (exception != null) throw exception;
}
为什么不好?因为您将丢失堆栈跟踪(它将显示异常是在当前方法中抛出的,而不是在WebClient中抛出的)。尽管如此,如果你不需要或者不关心stacktrace,这是一个可能的解决方案。
就地处理异常
你也可以创建一些方法来处理外部try-catch和下载的处理程序中的异常:
void HandleWebClientException(Exception exc)
{
...
}
try
{
ManualResetEvent mr = new ManualResetEvent(false);
mr.Reset();
using (WebClient wc = new WebClient())
{
wc.DownloadFileCompleted += ((sender, args) =>
{
if (args.Error == null)
{
File.Move(filePath, Path.ChangeExtension(filePath, ".jpg"));
mr.Set();
}
else
{
HandleWebClientException(args.Error);
}
});
wc.DownloadFileAsync(new Uri(string.Format("{0}/{1}", Settings1.Default.WebPhotosLocation, Path.GetFileName(f.FullName))), filePath);
mr.WaitOne();
}
}
catch (Exception ex)
{
HandleWebClientException(ex);
}
做对了
最好的办法是避免在WebClient
上使用void方法,因为你不能等待它们或应用一些延续。
这些方法在某种意义上是方便的,但它们迫使您使用具有同步构造的秘密解决方案,以使工作流较少依赖于不同的回调。
要使用async-await,您必须应用public Task<byte[]> DownloadDataTaskAsync(Uri address)
方法。
1。 await
可以获得数据的字节数组,以便以后手动保存,但这需要在应用程序中进行可靠的重做,以使其始终异步:
public async Task LoadFile()
{
try
{
using (WebClient wc = new WebClient())
{
var bytes = await wc.DownloadDataTaskAsync(new Uri(string.Format("{0}/{1}", Settings1.Default.WebPhotosLocation, Path.GetFileName(f.FullName))), filePath);
System.IO.File.WriteAllBytes(bytes); // Probably turn it into async too
}
}
catch (Exception ex)
{
//Catch my error here and handle it (display message box)
}
}
它将工作,但我不确定DownloadDataTaskAsync
是一个真正的异步方法。
2。所以你也可以考虑用同样的方法使用任务延续:
public Task LoadFile()
{
Task<Byte[]> bytesTask = wc.DownloadDataTaskAsync(new Uri(string.Format("{0}/{1}", Settings1.Default.WebPhotosLocation, Path.GetFileName(f.FullName))), filePath);
var success = bytesTask.ContinueWith((prev) =>
{
System.IO.File.WriteAllBytes(prev.Result);
},
TaskContinuationOptions.OnlyOnRanToCompletion);
var failure = bytesTask.ContinueWith(prev =>
{
MessageBox.Show //...
},
TaskContinuationOptions.OnlyOnFaulted);
return Task.WhenAny(success, failure);
}
注::如果你不需要异步加载文件,为什么不使用简单的阻塞方法public void DownloadFile(Uri address, string fileName)
呢?
你能做的是创建一个任务(一个异步操作),并使用ContinueWith指令来处理异常。这可能有点不可读
using (WebClient wc = new WebClient())
{
wc.DownloadFileCompleted += ((sender, args) =>
{
if (args.Error == null)
{
File.Move(filePath, Path.ChangeExtension(filePath, ".jpg"));
mr.Set();
}
else
{
//how to pass args.Error?
}
});
Task.Factory.StartNew(() => wc.DownloadFile(
new Uri(string.Format("{0}/{1}",
Settings1.Default.WebPhotosLocation,
Path.GetFileName(f.FullName))), filePath))
.ContinueWith(t => Console.WriteLine(t.Exception.Message));
}
然而,随着。net 4.5的引入,Webclient为你提供了一个基于任务的异步下载!
using (WebClient wc = new WebClient())
{
wc.DownloadFileCompleted += ((sender, args) =>
{
if (args.Error == null)
{
File.Move(filePath, Path.ChangeExtension(filePath, ".jpg"));
mr.Set();
}
else
{
//how to pass args.Error?
}
});
wc.DownloadFileTaskAsync(new Uri(string.Format("{0}/{1}",
Settings1.Default.WebPhotosLocation,
Path.GetFileName(f.FullName))),
filePath)
.ContinueWith(t => t.Exception.Message)
}
您应该使用await
和DownloadFileTaskAsync
:
try
{
using (WebClient wc = new WebClient())
{
await wc.DownloadFileTaskAsync(new Uri(string.Format("{0}/{1}", Settings1.Default.WebPhotosLocation, Path.GetFileName(f.FullName))), filePath);
}
}
catch (Exception ex)
{
//Catch my error here and handle it (display message box)
}
DownloadFileAsync使用基于事件的异步模式,你不能捕获异常,你可以得到异常抛出AsyncCompletedEventArgs。错误属性