使用WebClient.DownloadFileAsync时如何处理异常

时间:2015-05-29 16:33:58

标签: c# error-handling webclient

我正在使用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方法的错误传递给我的主要问题。这样做的正确方法是什么?

3 个答案:

答案 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)

您应该使用awaitDownloadFileTaskAsync

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属性