【问题标题】:Async function with DownloadStringAsync带有 DownloadStringAsync 的异步函数
【发布时间】:2016-11-11 09:57:42
【问题描述】:

我正在尝试什么

在我的 WPF 中,我抓取我的内部网络并查看是否可以访问 IP/URL。所以我用DownloadStringAsync 循环调用255 个IP。现在,每当我收到响应或超时时,我都想更新我的进度条(最大值为 255)。当我看到进度条在移动时,我的代码似乎适用于前 x 个(我相信大概是 10-15 个)IP

调用循环

try
   {
     while (i < 255)
     {
         var client = new WebClient();
         client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(GetInfo);
         client.DownloadStringAsync(new Uri("http://" + myIPNet + "." + i + ":1400/status/topology"));
         i++;
     }
   }
   catch (Exception ex)
   {
       Console.WriteLine(ex.Message);
   }

GetInfo 函数

private void GetInfo(object sender, DownloadStringCompletedEventArgs e)
{
    /* Each call, count up Global Ip Counter and move progressBar */
    countIps++;
    pbSearch.Value = countIps;

    /* Do Stuff with e.Result */
    ...

    /* Check if we have all IPs in net already */
    if (countIps == 255)
    {
        /* Reset progressBar */
        pbSearch.Value = 0;

        /* Enable Button  */
        btnGetAll.IsEnabled = true;
     }
 }

我找到了这个Asynchronous File Download with Progress Bar,我想我理解这个答案https://stackoverflow.com/a/9459441/1092632,但是这个进度条更新了一个正在进行的下载,关于如何将这个“转换”到我的案例有什么想法吗?

【问题讨论】:

  • 我发现您的代码存在多个问题。您在循环中创建了一个WebClient,但不释放它(它一个IDisposable)。您想直接从您的模型代码更新 ProgressBar,但这不是 WPF 应用程序的设计方式 - 请改用 MVVM 方法和数据 Bindings。

标签: c# wpf asynchronous


【解决方案1】:

我认为您的代码的主要问题是您希望 DownloadStringAsync 阻塞直到 DownloadStringCompleted 事件触发。根据函数的描述,这不会发生:

下载指定为 Uri 的资源。此方法不阻塞 调用线程。

实际上,您正在快速进行 255 个并发网络调用,然后在它们完成之前退出循环底部。

由于使用Event-based Asynchronous Pattern (EAP) 进行阻塞将需要对代码进行重大的重新架构(并显着增加复杂性),我鼓励您改用Task-based Asynchronous Pattern。 Stephen Toub 有一个很好的指南来将 WebClient 从 EAP 转换为 TAP 模式here

使用它,您可以按如下方式重写您的代码,并且应该会取得更大的成功:

var client = new WebClient();

while (i < 255)
{
    try
    {
        byte[] result = await client.DownloadDataTask(new Uri("http://" + myIPNet + "." + i + ":1400/status/topology"));
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }

    pbSearch.Value = i++;
}

/* Now we have all IPs */
/* Reset progressBar */
pbSearch.Value = 0;

/* Enable Button  */
btnGetAll.IsEnabled = true;

希望对你有帮助。

【讨论】:

  • 我想我理解这个概念并且能够实现一个工作版本。不过有两件事:1)不应该是byte[] result = await DownloadDataTask(client, new Uri("http://" + myIPNet + "." + i + ":1400/status/topology")); 和2)现在它真的很慢,我想是因为它在等待超时才能进入下一个?有什么办法可以解决这个问题?
  • 我认为 DownloadDataTask 被指定为扩展方法(第一个参数被限定为 'this'),因此它可以任意使用。是的,它会很慢,因为它会在任何没有响应的 IP 地址上超时。要解决此问题,您可能需要查看使用某种类型的 ICMP 消息(即 ping)而不是 HTTP 下载来确定客户端是否存在于特定地址。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-01
  • 2016-06-17
  • 1970-01-01
  • 2021-03-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多