C# 使用WebClient.DownloadFileAsync时如何处理异常
我正在使用C# 使用WebClient.DownloadFileAsync时如何处理异常,c#,error-handling,webclient,C#,Error Handling,Webclient,我正在使用WebClient以以下方式从internet下载一些文件: try { ManualResetEvent mr = new ManualResetEvent(false); mr.Reset(); using (WebClient wc = new WebClient()) { wc.DownloadFileCompleted += ((sender, args) => { if
WebClient
以以下方式从internet下载一些文件:
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)
}
但是我似乎无法将错误从我的annonymous
DownloadFileCompleted
方法传递到我的主要捕获。正确的方法是什么?您应该使用wait
和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使用,您无法捕获异常,您可以获取异常抛出属性您可以做的是创建一个任务(异步操作)并使用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)
}
带回缩的不良溶液
可以将异常保存在lambda外部定义的某个变量中。然后可以将其重新收回:
Exception exc = null;
using (WebClient wc = new WebClient())
{
wc.DownloadFileCompleted += ((sender, args) =>
...
mr.WaitOne();
if (exception != null) throw exception;
}
为什么不好?因为您将丢失stacktrace(它将显示异常是在当前方法中引发的,而不是在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);
}
做对了
最好的办法是避免在上使用void方法,因为您不能在它们上使用void方法或应用某些方法
这些方法在某种意义上是方便的,但它们迫使您使用带有同步结构的秘密解决方案,以减少工作流对不同回调的依赖
要使用AsyncWait,您必须应用方法
您可以:
1。等待
获取数据的字节数组,以便以后手动保存,但这需要在应用程序中进行彻底的返工,以使其:
它会起作用,但我不确定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);
}
公共任务加载文件()
{
Task bytesTask=wc.DownloadDataTaskAsync(新Uri(string.Format(“{0}/{1}”),Settings1.Default.WebPhotosLocation,Path.GetFileName(f.FullName)),filePath);
var success=bytesTask.ContinueWith((上一个)=>
{
System.IO.File.writealBytes(上一个结果);
},
TaskContinuationOptions.OnlyOnRanToCompletion);
var failure=bytesTask.ContinueWith(上一个=>
{
MessageBox.Show/。。。
},
TaskContinuationOptions.OnlyOnFaulted);
返回任务。何时(成功、失败);
}
p.S.:如果不需要异步加载文件,为什么不使用简单的阻塞方法呢?回答得很好!我使用的是.NET4,所以不能使用
wait
关键字。我可能会选择“糟糕的解决方案”,因为我不需要StackTrace
。我不使用阻塞方法的原因也是因为我需要用进度更新UI(我在示例中没有提到)@user1您可以在.Net 4中使用async/wait。只需在Nuget中运行安装包Microsoft.Bcl.Async
命令。有关更多详细信息,请参见此
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);
}