使用WebClient.DownloadFileAsync时如何处理异常 [英] How to deal with exceptions when using WebClient.DownloadFileAsync

查看:185
本文介绍了使用WebClient.DownloadFileAsync时如何处理异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 WebClient 通过以下方式从Internet下载一些文件:

I am downloading some files from the internet using a WebClient in the following way:

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 达到我的主要目标。正确的方法是什么?

But I cannot seem to pass the error from my annonymous DownloadFileCompleted method up to my main catch. What is the correct way to do this?

推荐答案

抛出错误的解决方案



您可以将异常保存在lambda之外定义的某些变量中。然后可以将其重新抛出:

Bad solution with rethrowing

You can save the exception in some variable defined outside the lambda. Then it can be rethrown:

Exception exc = null;
using (WebClient wc = new WebClient())
{
      wc.DownloadFileCompleted += ((sender, args) =>
      ...

      mr.WaitOne();

      if (exception != null) throw exception;
}

为什么不好呢?因为您将松开stacktrace(它将显示在当前方法而不是WebClient中引发了异常)。

Why is it bad? Because you will loose the stacktrace(it will show that the exception was thrown in the current method, not in the WebClient). Still, if you do not need or do not care about stacktrace, it is possible solution.

您也可以只创建一些可以在外部try-catch和下载的处理程序中处理异常的方法:

You can also just create some method that will handle the exception in both the outer try-catch and in the downloaded handler:

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 ,因为您不能等待,或在其中应用一些连续

Doing it right

The best idea is to avoid void methods on WebClient, because you can't await on them or apply some continuation.

从某种意义上说,这种方法很方便,但是它们迫使您使用具有同步结构的秘密解决方案

Such methods are convenient in some sense, but they force you to use clandestine solutions with synchronization constructs to make the workflow less dependent on different callbacks.

要使用异步等待,您将必须应用 公共任务< byte []> DownloadDataTaskAsync(Uri地址) 方法。

To use async-await you will have to apply public Task<byte[]> DownloadDataTaskAsync(Uri address) method.

您可以:

1。 等待来获取数据的字节数组,以便稍后手动保存,但是需要在应用程序中进行大量修改才能使其成为一路异步

1. await it to get the byte array of data to save it later manually, but it will require a solid rework in your application to make it async all the way:

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 是真正的异步方法。

It will work, but I am not sure that DownloadDataTaskAsync is a true async method.

2。。因此,您也可以考虑使用< a href = https://msdn.microsoft.com/en-us/library/ee372288(v=vs.110).aspx rel = nofollow>任务继续,其方法相同:

2. So you may also consider using Task Continuations with the same method:

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);
}

PS:为什么你不只是使用简单的阻止方法 public void DownloadFile(Uri地址,字符串fileName) 是否不需要异步加载文件?

P.S.: And why don't you just use the simple blocking method public void DownloadFile(Uri address, string fileName) if you have no need to load files asynchronously?

这篇关于使用WebClient.DownloadFileAsync时如何处理异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆