use*_*er1 5 c# error-handling webclient
我使用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)
}
Run Code Online (Sandbox Code Playgroud)
但我似乎无法将错误从我的匿名DownloadFileCompleted方法传递到我的主要捕获.这样做的正确方法是什么?
您可以将异常保存在 lambda 之外定义的某个变量中。然后它可以被重新抛出:
Exception exc = null;
using (WebClient wc = new WebClient())
{
wc.DownloadFileCompleted += ((sender, args) =>
...
mr.WaitOne();
if (exception != null) throw exception;
}
Run Code Online (Sandbox Code Playgroud)
为什么不好?因为您将丢失堆栈跟踪(它将显示异常是在当前方法中抛出的,而不是在 WebClient 中)。尽管如此,如果您不需要或不关心堆栈跟踪,这是可能的解决方案。
您还可以创建一些方法来处理外部 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);
}
Run Code Online (Sandbox Code Playgroud)
最好的主意是避免在 上使用 void 方法WebClient,因为您不能等待它们或应用一些continuation。
此类方法在某种意义上很方便,但它们迫使您使用带有同步构造的秘密解决方案,以减少工作流对不同回调的依赖。
要使用 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)
}
}
Run Code Online (Sandbox Code Playgroud)
它会起作用,但我不确定这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);
}
Run Code Online (Sandbox Code Playgroud)
PS:public void DownloadFile(Uri address, string fileName)如果你不需要异步加载文件,你为什么不使用简单的阻塞方法?
| 归档时间: |
|
| 查看次数: |
9819 次 |
| 最近记录: |