异步下载功能,怎么做? VB.NET

Async download function, how to do it? VB.NET

作为大学项目,我正在研究冠状病毒统计仪表板,我在从具有统计信息的站点下载异步源数据时遇到了一些问题。 好吧,我自己没搞懂怎么做。

我尝试创建自己的 class,其功能是创建多个异步 Web 请求 然后等到他们全部完成,然后 return 所有这些请求的结果。

Imports System.Net.WebClient
Imports System.Net
Public Class AsyncDownload
    Private result As New Collection
    Private Sub DownloadCompletedHander(ByVal sender As Object, ByVal e As System.Net.DownloadStringCompletedEventArgs)
        If e.Cancelled = False AndAlso e.Error Is Nothing Then
            Dim myString As String = CStr(e.Result)
            result.Add(myString, sender.Headers.Item("source"))
        End If
    End Sub

    Public Function Load(sources As Array, keys As Array) As Collection
        Dim i = 0
        Dim WebClients As New Collection
        While (i < sources.Length)
            Dim newClient As New WebClient
            newClient.Headers.Add("source", keys(i))
            newClient.Headers.Add("sourceURL", sources(i))
            AddHandler newClient.DownloadStringCompleted, AddressOf DownloadCompletedHander
            WebClients.Add(newClient)
            i = i + 1
        End While
        i = 1
        For Each client As WebClient In WebClients
            Dim url As String = client.Headers.Item("sourceURL")
            client.DownloadStringAsync(New Uri(url))
        Next
        While (result.Count < WebClients.Count)
        End While
        Return result
    End Function
End Class

它用于:

    Dim result As New Collection
    Private Sub test() Handles Me.Load
        Dim downloader As New CoronaStatisticsGetter.AsyncDownload
        result = downloader.Load({"https://opendata.digilugu.ee/covid19/vaccination/v3/opendata_covid19_vaccination_total.json"}, {"Nationalwide Data"})
    End Sub

它应该像这样工作:

  1. 我创建了我的 class 的新实例。
  2. 调用此class
  3. 的函数加载
  4. Funciton Load 为每个 url 创建 System.Net.WebClient 实例并添加为处理程序 DownloadCompletedHander
  5. 函数 Load 去调用每个客户端的 DownloadStringAsync
  6. 函数加载在 While 循环中等待,直到结果集合项计数小于输入 url 的数量
  7. 如果结果中的项目计数与 urls 数字相同,这意味着所有内容都已下载,因此它会中断循环并且 returns 所有请求的数据

问题是它不起作用,它只是无休止地停留在 while 循环中,而且我看到使用调试收集结果没有更新(它的大小总是 0)

同时,当我尝试在不使用 class 的情况下异步下载它时,一切正常:

Private Sub Download() 'Handles Me.Load
        Dim wc As New System.Net.WebClient
        wc.Headers.Add("source", "VaccinationByAgeGroup")
        AddHandler wc.DownloadStringCompleted, AddressOf DownloadCompletedHander
        wc.DownloadStringAsync(New Uri("https://opendata.digilugu.ee/covid19/vaccination/v3/opendata_covid19_vaccination_agegroup.json"))
End Sub

有人能告诉我为什么它不起作用以及问题出在哪里吗?

下面显示了如何使用 System.Net.WebClient with Task 从 URL.

下载字符串(即:数据)

添加项目引用 (System.Net)

VS 2019:

  • 在 VS 菜单中,单击 项目
  • Select 添加参考...
  • Select 程序集
  • 勾选System.Net
  • 单击确定

创建一个class(名称:DownloadedData.vb)

Public Class DownloadedData
    Public Property Data As String
    Public Property Url As String
End Class

创建一个class(名称:HelperWebClient.vb)

Public Class HelperWebClient

    Public Async Function DownloadDataAsync(urls As List(Of String)) As Task(Of List(Of DownloadedData))
        Dim allTasks As List(Of Task) = New List(Of Task)
        Dim downloadedDataList As List(Of DownloadedData) = New List(Of DownloadedData)

        For i As Integer = 0 To urls.Count - 1
            'set value
            Dim url As String = urls(i)
            Debug.WriteLine(String.Format("[{0}]: Adding {1}", i, url))

            Dim t = Task.Run(Async Function()
                                 'create new instance
                                 Dim wc As WebClient = New WebClient()

                                 'await download
                                 Dim result = Await wc.DownloadStringTaskAsync(url)
                                 Debug.WriteLine(url & " download complete")

                                 'ToDo: add desired code
                                 'add
                                 downloadedDataList.Add(New DownloadedData() With {.Url = url, .Data = result})
                             End Function)
            'add
            allTasks.Add(t)
        Next

        For i As Integer = 0 To allTasks.Count - 1
            'wait for a task to complete
            Dim t = Await Task.WhenAny(allTasks)

            'remove from List
            allTasks.Remove(t)

            'write data to file
            'Note: The following is only for testing.
            'The index in urls won't necessarily correspond to the filename below
            Dim filename As String = System.IO.Path.Combine("C:\Temp", String.Format("CoronavirusData_{0:00}.txt", i))
            System.IO.File.WriteAllText(filename, downloadedDataList(i).Data)

            Debug.WriteLine($"[{i}]: Filename: {filename}")
        Next

        Debug.WriteLine("all tasks complete")

        Return downloadedDataList
    End Function
End Class

用法:

Private Async Sub btnRun_Click(sender As Object, e As EventArgs) Handles btnRun.Click
    Dim helper As HelperWebClient = New HelperWebClient()

    Dim urls As List(Of String) = New List(Of String)
    urls.Add("https://opendata.digilugu.ee/covid19/vaccination/v3/opendata_covid19_vaccination_total.json")
    urls.Add("https://api.covidtracking.com/v2/states.json")
    urls.Add("https://covidtrackerapi.bsg.ox.ac.uk/api/v2/stringency/date-range/2020-01-01/2022-03-01")
    urls.Add("http://covidsurvey.mit.edu:5000/query?age=20-30&gender=all&country=US&signal=locations_would_attend")

    Dim downloadedDataList = Await helper.DownloadDataAsync(urls)
    Debug.WriteLine("Complete")
End Sub

资源:

  • How do I wait for something to finish in C#?