我正在使用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
方法的错误传递给我的主要问题。这样做的正确方法是什么?
答案 0 :(得分:3)
您可以做的是创建一个Task(异步操作)并使用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)
}
答案 1 :(得分:3)
您可以将异常保存在lambda外部定义的某个变量中。然后它可以被重新抛出:
$(".btn1").click(function(){...}
为什么不好?因为你将松散堆栈跟踪(它将显示在当前方法中抛出异常,而不是在WebClient中)。不过,如果你不需要或不关心堆栈跟踪,那么这是可能的解决方案。
您还可以创建一些方法来处理外部try-catch和下载的处理程序中的异常:
Exception exc = null;
using (WebClient wc = new WebClient())
{
wc.DownloadFileCompleted += ((sender, args) =>
...
mr.WaitOne();
if (exception != null) throw exception;
}
最好的办法是避免在WebClient
上使用无效方法,因为您不能await对其进行操作或应用某些continuation。
此类方法在某种意义上很方便,但它们会强制您使用具有同步构造的秘密解决方案,以使工作流程更少依赖于不同的回调。
要使用async-await,您必须应用public Task<byte[]> DownloadDataTaskAsync(Uri address)
方法。
你可以:
1。 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);
}
要获取数据的字节数组以便稍后手动保存,但是需要在应用程序中进行可靠的返工才能使其成为async all the way:
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)
}
}
是否是真正的异步方法。
2。因此,您也可以考虑使用Task Continuations使用相同的方法:
DownloadDataTaskAsync
P.S。:如果您不需要异步加载文件,为什么不使用简单的阻止方法public void DownloadFile(Uri address, string fileName)
?
答案 2 :(得分:1)
您应该使用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使用Event-based Asynchronous Pattern,你无法捕获异常,你可以获得异常抛出AsyncCompletedEventArgs.Error属性