Przewodnik: uzyskiwanie dostępu do Sieci za pomocą Async i Await (Visual Basic)

Programy asynchroniczne można łatwiej i intuicyjnie pisać przy użyciu funkcji async/await. Można napisać kod asynchroniczny, który wygląda jak kod synchroniczny, i pozwolić kompilatorowi na obsługę trudnych funkcji wywołania zwrotnego i kontynuacji, które zwykle wiąże się z kodem asynchronicznym.

Aby uzyskać więcej informacji na temat funkcji asynchronicznej, zobacz Programowanie asynchroniczne z Async i Await (Visual Basic).

Ten przewodnik rozpoczyna się od synchronicznej aplikacji Windows Presentation Foundation (WPF), która sumuje liczbę bajtów na liście witryn internetowych. Przewodnik następnie konwertuje aplikację na rozwiązanie asynchroniczne przy użyciu nowych funkcji.

Aplikacje można opracowywać, wykonując przewodnik lub pobierając przykład z przykładowej przeglądarki .NET. Przykładowy kod znajduje się w projekcie SerialAsyncExample.

W tym przewodniku należy wykonać następujące zadania:

Pełny przykład asynchroniczny można znaleźć w sekcji Przykład.

Wymagania wstępne

Visual Studio komputerze musi być zainstalowany program 2012 lub nowszy. Aby uzyskać więcej informacji, zobacz stronę Visual Studio pliki do pobrania.

Tworzenie aplikacji WPF

  1. Uruchom program Visual Studio.

  2. Na pasku menu wybierz pozycję Plik, Nowy, Project.

    Zostanie otwarte Project nowe okno dialogowe.

  3. W okienku Zainstalowane szablony wybierz pozycję Visual Basic, a następnie wybierz pozycję Aplikacja WPF z listy typów projektów.

  4. W polu tekstowym Nazwa wprowadź AsyncExampleWPF , a następnie wybierz przycisk OK.

    Nowy projekt zostanie wyświetlony w Eksplorator rozwiązań.

Projektowanie prostego systemu WPF MainWindow

  1. W edytorze Visual Studio Code wybierz kartę MainWindow.xaml.

  2. Jeśli okno Przybornik nie jest widoczne, otwórz menu Widok, a następnie wybierz pozycję Przybornik.

  3. Dodaj kontrolkę Przycisk i kontrolkę TextBox do okna MainWindow.

  4. Wyróżnij kontrolkę TextBox i w oknie Właściwości ustaw następujące wartości:

    • Ustaw właściwość Name na resultsTextBox wartość .

    • Ustaw właściwość Height na wartość 250.

    • Ustaw właściwość Width na wartość 500.

    • Na karcie Tekst określ czcionkę o stałej przestrzeni, taką jak Konsola Lucida lub Global Monospace.

  5. Wyróżnij kontrolkę Przycisk i w oknie Właściwości ustaw następujące wartości:

    • Ustaw właściwość Name na startButton wartość .

    • Zmień wartość właściwości Content z Button na Start.

  6. Umieść pole tekstowe i przycisk tak, aby oba pojawiały się w oknie MainWindow.

    Aby uzyskać więcej informacji na temat interfejsu projektant XAML WPF, zobacz Tworzenie interfejsu użytkownika przy użyciu projektant XAML.

Dodawanie odwołania

  1. W Eksplorator rozwiązań wyróżnij nazwę projektu.

  2. Na pasku menu wybierz pozycję , Project dodaj odwołanie.

    Zostanie wyświetlone okno dialogowe Menedżer odwoływać.

  3. W górnej części okna dialogowego sprawdź, czy projekt jest przeznaczony dla .NET Framework 4.5 lub wyższego.

  4. W obszarze Zestawy wybierz pozycję Framework, jeśli nie została jeszcze wybrana.

  5. Na liście nazw zaznacz pole wyboru System.Net.Http.

  6. Wybierz przycisk OK, aby zamknąć okno dialogowe.

Dodawanie niezbędnych instrukcji Imports

  1. W Eksplorator rozwiązań otwórz menu skrótów mainWindow.xaml.vb, a następnie wybierz pozycję Wyświetl kod.

  2. Dodaj następujące Imports instrukcje w górnej części pliku kodu, jeśli jeszcze nie są obecne.

    Imports System.Net.Http
    Imports System.Net
    Imports System.IO
    

Tworzenie aplikacji synchronicznej

  1. W oknie projektowania MainWindow.xaml kliknij dwukrotnie przycisk Start, aby utworzyć program obsługi zdarzeń w startButton_Click pliku MainWindow.xaml.vb.

  2. W pliku MainWindow.xaml.vb skopiuj następujący kod do treści startButton_Click pliku :

    resultsTextBox.Clear()
    SumPageSizes()
    resultsTextBox.Text &= vbCrLf & "Control returned to startButton_Click."
    

    Kod wywołuje metodę , która kieruje SumPageSizes aplikacją, i wyświetla komunikat, gdy kontrolka powraca do startButton_Click metody .

  3. Kod rozwiązania synchronicznego zawiera następujące cztery metody:

    • SumPageSizes, który pobiera listę adresów URL stron internetowych z adresu , a następnie wywołuje i w SetUpURLList GetURLContents celu DisplayResults przetwarzania każdego adresu URL.

    • SetUpURLList, który tworzy i zwraca listę adresów internetowych.

    • GetURLContents, który pobiera zawartość każdej witryny internetowej i zwraca zawartość jako tablicę bajtów.

    • DisplayResults, który wyświetla liczbę bajtów w tablicy bajtów dla każdego adresu URL.

    Skopiuj następujące cztery metody, a następnie wklej je w obszarze startButton_Click obsługi zdarzeń w pliku MainWindow.xaml.vb:

    Private Sub SumPageSizes()
    
        ' Make a list of web addresses.
        Dim urlList As List(Of String) = SetUpURLList()
    
        Dim total = 0
        For Each url In urlList
            ' GetURLContents returns the contents of url as a byte array.
            Dim urlContents As Byte() = GetURLContents(url)
    
            DisplayResults(url, urlContents)
    
            ' Update the total.
            total += urlContents.Length
        Next
    
        ' Display the total count for all of the web addresses.
        resultsTextBox.Text &= String.Format(vbCrLf & vbCrLf & "Total bytes returned:  {0}" & vbCrLf, total)
    End Sub
    
    Private Function SetUpURLList() As List(Of String)
    
        Dim urls = New List(Of String) From
            {
                "https://msdn.microsoft.com/library/windows/apps/br211380.aspx",
                "https://msdn.microsoft.com",
                "https://msdn.microsoft.com/library/hh290136.aspx",
                "https://msdn.microsoft.com/library/ee256749.aspx",
                "https://msdn.microsoft.com/library/hh290138.aspx",
                "https://msdn.microsoft.com/library/hh290140.aspx",
                "https://msdn.microsoft.com/library/dd470362.aspx",
                "https://msdn.microsoft.com/library/aa578028.aspx",
                "https://msdn.microsoft.com/library/ms404677.aspx",
                "https://msdn.microsoft.com/library/ff730837.aspx"
            }
        Return urls
    End Function
    
    Private Function GetURLContents(url As String) As Byte()
    
        ' The downloaded resource ends up in the variable named content.
        Dim content = New MemoryStream()
    
        ' Initialize an HttpWebRequest for the current URL.
        Dim webReq = CType(WebRequest.Create(url), HttpWebRequest)
    
        ' Send the request to the Internet resource and wait for
        ' the response.
        ' Note: you can't use HttpWebRequest.GetResponse in a Windows Store app.
        Using response As WebResponse = webReq.GetResponse()
            ' Get the data stream that is associated with the specified URL.
            Using responseStream As Stream = response.GetResponseStream()
                ' Read the bytes in responseStream and copy them to content.
                responseStream.CopyTo(content)
            End Using
        End Using
    
        ' Return the result as a byte array.
        Return content.ToArray()
    End Function
    
    Private Sub DisplayResults(url As String, content As Byte())
    
        ' Display the length of each website. The string format
        ' is designed to be used with a monospaced font, such as
        ' Lucida Console or Global Monospace.
        Dim bytes = content.Length
        ' Strip off the "https://".
        Dim displayURL = url.Replace("https://", "")
        resultsTextBox.Text &= String.Format(vbCrLf & "{0,-58} {1,8}", displayURL, bytes)
    End Sub
    

Testowanie rozwiązania synchronicznego

  1. Wybierz klawisz F5, aby uruchomić program, a następnie wybierz przycisk Uruchom.

    Powinny zostać wyświetlone dane wyjściowe podobne do poniższej listy:

    msdn.microsoft.com/library/windows/apps/br211380.aspx        383832
    msdn.microsoft.com                                            33964
    msdn.microsoft.com/library/hh290136.aspx               225793
    msdn.microsoft.com/library/ee256749.aspx               143577
    msdn.microsoft.com/library/hh290138.aspx               237372
    msdn.microsoft.com/library/hh290140.aspx               128279
    msdn.microsoft.com/library/dd470362.aspx               157649
    msdn.microsoft.com/library/aa578028.aspx               204457
    msdn.microsoft.com/library/ms404677.aspx               176405
    msdn.microsoft.com/library/ff730837.aspx               143474
    
    Total bytes returned:  1834802
    
    Control returned to startButton_Click.
    

    Zwróć uwagę, że wyświetlenie liczników może potrwać kilka sekund. W tym czasie wątek interfejsu użytkownika jest blokowany podczas oczekiwania na pobranie żądanych zasobów. W związku z tym po wybraniu przycisku Uruchom nie można przenosić, maksymalizować, minimalizować ani nawet zamykać okna wyświetlania. Te wysiłki nie powiodą się, dopóki nie zaczną pojawiać się liczby bajtów. Jeśli witryna internetowa nie odpowiada, nie ma żadnego wskazania, która witryna zakończyła się niepowodzeniem. Trudno jest nawet zatrzymać oczekiwanie i zamknąć program.

Konwertowanie obiektów GetURLContent na metodę asynchroniczną

  1. Aby przekonwertować rozwiązanie synchroniczne na rozwiązanie asynchroniczne, najlepszym miejscem do rozpoczęcia jest metoda , ponieważ wywołania metody i metody to miejsce, w którym aplikacja uzyskuje dostęp GetURLContents HttpWebRequest.GetResponse do Stream.CopyTo Internetu. Metoda .NET Framework ułatwia konwersję, udostępniając asynchroniczne wersje obu metod.

    Aby uzyskać więcej informacji na temat metod używanych w GetURLContents programie , zobacz WebRequest .

    Uwaga

    Podczas pracy z krokami w tym przewodniku pojawia się kilka błędów kompilatora. Możesz je zignorować i kontynuować przewodnik.

    Zmień metodę wywoływaną w trzecim wierszu polecenia z na GetURLContents GetResponse asynchroniczną metodę opartą na GetResponseAsync zadaniach.

    Using response As WebResponse = webReq.GetResponseAsync()
    
  2. GetResponseAsync Zwraca wartość Task<TResult> . W tym przypadku zadanie zwraca zmienną, TResult , i ma typ WebResponse . Zadanie jest obietnicą uzyskania rzeczywistego obiektu po pobraniu żądanych danych i zakończeniu WebResponse zadania.

    Aby pobrać wartość z zadania, zastosuj operator Await do wywołania WebResponse , jak GetResponseAsync pokazano w poniższym kodzie.

    Using response As WebResponse = Await webReq.GetResponseAsync()
    

    Operator Await wstrzymuje wykonywanie bieżącej metody GetURLContents , do momentu ukończenia oczekiwanego zadania. W międzyczasie sterowanie powraca do wywołującego bieżącej metody. W tym przykładzie bieżąca metoda to GetURLContents , a wywołujący to SumPageSizes . Po zakończeniu zadania obiekt obietnicy jest wytwarzanych jako wartość oczekiwanego zadania i WebResponse przypisywany do zmiennej response .

    Poprzednią instrukcje można oddzielić na następujące dwie instrukcje, aby wyjaśnić, co się stanie.

    Dim responseTask As Task(Of WebResponse) = webReq.GetResponseAsync()
    Using response As WebResponse = Await responseTask
    

    Wywołanie metody webReq.GetResponseAsync zwraca wartość lub Task(Of WebResponse) Task<WebResponse> . Następnie Await operator jest stosowany do zadania w celu pobrania WebResponse wartości.

    Jeśli wykonanie metody asynchronicznej nie zależy od ukończenia zadania, metoda może kontynuować pracę między tymi dwiema instrukcje, po wywołaniu metody async i przed zastosowaniem operatora await. Przykłady można znaleźć w tematach How to: Make Multiple Web Requests in Parallel by Using Async and Await (Visual Basic) (Jak wykonać wiele równoległych żądań internetowych za pomocą Async i Await ( Visual Basic) i How to: Extend the Async Walkthrough by Using Task.WhenAll (Visual Basic)(Jak rozszerzyć przewodnik asynchroniczny przy użyciu funkcji Task.WhenAll (Visual Basic).

  3. Ponieważ operator został Await dodany w poprzednim kroku, występuje błąd kompilatora. Operatora można używać tylko w metodach oznaczonych za pomocą modyfikatora Async. Zignoruj błąd podczas powtarzania kroków konwersji, aby zastąpić wywołanie do CopyTo wywołaniem . CopyToAsync

    • Zmień nazwę metody, która jest wywoływana na CopyToAsync .

    • Metoda CopyTo or CopyToAsync kopiuje bajty do argumentu , i nie content zwraca znaczącej wartości. W wersji synchronicznej wywołanie do jest CopyTo prostą instrukcje, która nie zwraca wartości. Wersja asynchroniczna CopyToAsync zwraca wartość Task . Zadanie działa jak "Task(void)" i umożliwia oczekiwanie na metodę. Zastosuj Await lub do wywołania , jak await CopyToAsync pokazano w poniższym kodzie.

      Await responseStream.CopyToAsync(content)
      

      Poprzednia instrukcja skraca następujące dwa wiersze kodu.

      ' CopyToAsync returns a Task, not a Task<T>.
      Dim copyTask As Task = responseStream.CopyToAsync(content)
      
      ' When copyTask is completed, content contains a copy of
      ' responseStream.
      Await copyTask
      
  4. Pozostało tylko dostosować GetURLContents sygnaturę metody. Operatora można używać Await tylko w metodach oznaczonych za pomocą modyfikatora Async. Dodaj modyfikator , aby oznaczyć metodę jako metodę asynchroniczną, jak pokazano w poniższym kodzie.

    Private Async Function GetURLContents(url As String) As Byte()
    
  5. Zwracany typ metody asynchronicznej może być tylko Task typu , Task<TResult> . W Visual Basic metoda musi być metodą , która zwraca wartość lub , lub metoda Function Task musi być metodą Task(Of T) Sub . Zazwyczaj metoda jest używana tylko w obsłudze zdarzeń Sub asynchronicznych, jeśli Sub jest to wymagane. W innych przypadkach użyjemy instrukcji , jeśli ukończona metoda ma instrukcji Return, która zwraca wartość typu T, a jeśli ukończona metoda nie zwraca Task(T) Task znaczącej wartości.

    Aby uzyskać więcej informacji, zobacz Asynchroniczne typy zwracane (Visual Basic).

    Metoda GetURLContents ma instrukcji return, a instrukcja zwraca tablicę bajtów. W związku z tym zwracany typ wersji asynchronicznej to Task(T), gdzie T jest tablicą bajtów. W sygnaturze metody należy wprowadzić następujące zmiany:

    • Zmień zwracany typ na Task(Of Byte()) .

    • Zgodnie z konwencją metody asynchroniczne mają nazwy, które kończą się na "Async", więc zmień nazwę metody GetURLContentsAsync .

    Poniższy kod przedstawia te zmiany.

    Private Async Function GetURLContentsAsync(url As String) As Task(Of Byte())
    

    W przypadku tych kilku zmian konwersja metody na GetURLContents metodę asynchroniczną jest ukończona.

Konwertowanie wartości SumPageSizes na metodę asynchroniczną

  1. Powtórz kroki z poprzedniej procedury dla SumPageSizes . Najpierw zmień wywołanie metody na GetURLContents wywołanie asynchroniczne.

    • Zmień nazwę metody wywoływanej z na GetURLContents , jeśli jeszcze tego nie GetURLContentsAsync zrobiono.

    • Zastosuj Await do zadania, które GetURLContentsAsync zwraca wartość w celu uzyskania wartości tablicy bajtów.

    Poniższy kod przedstawia te zmiany.

    Dim urlContents As Byte() = Await GetURLContentsAsync(url)
    

    Poprzednie przypisanie skraca następujące dwa wiersze kodu.

    ' GetURLContentsAsync returns a task. At completion, the task
    ' produces a byte array.
    Dim getContentsTask As Task(Of Byte()) = GetURLContentsAsync(url)
    Dim urlContents As Byte() = Await getContentsTask
    
  2. W sygnaturze metody należy wprowadzić następujące zmiany:

    • Oznacz metodę Async modyfikatorem .

    • Dodaj "Async" do nazwy metody.

    • Nie ma zmiennej zwracanej przez zadanie T, tym razem dlatego, że nie zwraca wartości SumPageSizesAsync dla T. (Metoda nie ma Return instrukcji ). Jednak metoda musi zwrócić , aby Task można było czekać. W związku z tym zmień typ metody z Sub na Function . Zwracany typ funkcji to Task .

    Poniższy kod przedstawia te zmiany.

    Private Async Function SumPageSizesAsync() As Task
    

    Konwersja SumPageSizes na wartość SumPageSizesAsync jest ukończona.

Konwertowanie startButton_Click na metodę asynchroniczną

  1. W programie obsługi zdarzeń zmień nazwę wywoływanej metody z na SumPageSizes , jeśli jeszcze tego nie SumPageSizesAsync zrobiono.

  2. Ponieważ SumPageSizesAsync metoda jest metodą asynchroniczną, zmień kod w programie obsługi zdarzeń, aby oczekiwał na wynik.

    Wywołanie do SumPageSizesAsync dubluje wywołanie w CopyToAsync GetURLContentsAsync . Wywołanie zwraca wartość Task , a nie Task(T) .

    Podobnie jak w poprzednich procedurach, wywołanie można przekonwertować przy użyciu jednej instrukcji lub dwóch instrukcji. Poniższy kod przedstawia te zmiany.

    ' One-step async call.
    Await SumPageSizesAsync()
    
    ' Two-step async call.
    Dim sumTask As Task = SumPageSizesAsync()
    Await sumTask
    
  3. Aby zapobiec przypadkowemu ponownemu wejrzeniu operacji, dodaj następującą instrukcje w górnej części, aby startButton_Click wyłączyć przycisk Start.

    ' Disable the button until the operation is complete.
    startButton.IsEnabled = False
    

    Przycisk na końcu procedury obsługi zdarzeń można w trybie ponownego wł.

    ' Reenable the button in case you want to run the operation again.
    startButton.IsEnabled = True
    

    Aby uzyskać więcej informacji na temat ponownego wejrzenia, zobacz Handling Reentrancy in Async Apps (Visual Basic) (Obsługa ponownegowejrzeń w aplikacjach asynchronicznych (Visual Basic).

  4. Na koniec dodaj Async modyfikator do deklaracji , aby program obsługi zdarzeń oczekiwał na . SumPagSizesAsync

    Async Sub startButton_Click(sender As Object, e As RoutedEventArgs) Handles startButton.Click
    

    Zazwyczaj nazwy programów obsługi zdarzeń nie są zmieniane. Zwracany typ nie jest zmieniany na , ponieważ procedury obsługi zdarzeń Task muszą być Sub procedurami w Visual Basic.

    Konwersja projektu z przetwarzania synchronicznego na asynchroniczna jest ukończona.

Testowanie rozwiązania asynchronicznego

  1. Wybierz klawisz F5, aby uruchomić program, a następnie wybierz przycisk Uruchom.

  2. Powinny pojawić się dane wyjściowe podobne do danych wyjściowych rozwiązania synchronicznego. Zwróć jednak uwagę na następujące różnice.

    • Wyniki nie wszystkie występują w tym samym czasie, po zakończeniu przetwarzania. Na przykład oba programy zawierają wiersz w startButton_Click , który wyczyści pole tekstowe. Celem jest wyczyszczenie pola tekstowego między przebiegami, jeśli wybierzesz przycisk Uruchom po raz drugi, po tym, jak pojawi się jeden zestaw wyników. W wersji synchronicznej pole tekstowe jest czyszowane tuż przed tym, jak liczniki pojawiają się po raz drugi, gdy pobieranie zostanie ukończone, a wątek interfejsu użytkownika może wykonać inną pracę. W wersji asynchronicznej pole tekstowe jest czyszczysz natychmiast po wybraniu przycisku Uruchom.

    • Co najważniejsze, wątek interfejsu użytkownika nie jest blokowany podczas pobierania. Okno można przenosić lub zmieniać ich rozmiar podczas pobierania, zliczania i wyświetlania zasobów internetowych. Jeśli jedna z witryn internetowych działa wolno lub nie odpowiada, możesz anulować operację, wybierając przycisk Zamknij (x w czerwonym polu w prawym górnym rogu).

Zastąp metodę GetURLContentsAsync metodą .NET Framework metodę

  1. W .NET Framework wiele metod asynchronicznych, których można użyć. Jedna z nich, HttpClient.GetByteArrayAsync(String) metoda , robi tylko to, czego potrzebujesz w tym przewodniku. Można go użyć zamiast metody GetURLContentsAsync utworzonej we wcześniejszej procedurze.

    Pierwszym krokiem jest utworzenie HttpClient obiektu w SumPageSizesAsync metodzie . Dodaj następującą deklarację na początku metody .

    ' Declare an HttpClient object and increase the buffer size. The
    ' default buffer size is 65,536.
    Dim client As HttpClient =
        New HttpClient() With {.MaxResponseContentBufferSize = 1000000}
    
  2. W SumPageSizesAsync, metodzie zastąp wywołanie metody GetURLContentsAsync wywołaniem metody HttpClient .

    Dim urlContents As Byte() = Await client.GetByteArrayAsync(url)
    
  3. Usuń napisaną GetURLContentsAsync metodę lub nadaj jej komentarz.

  4. Wybierz klawisz F5, aby uruchomić program, a następnie wybierz przycisk Uruchom.

    Zachowanie tej wersji projektu powinno odpowiadać zachowaniu opisanemu w procedurze "Aby przetestować rozwiązanie asynchroniczne", ale z jeszcze mniejszym nakładem pracy ze strony użytkownika.

Przykład

Poniżej przedstawiono pełny przykład przekonwertowanych rozwiązań asynchronicznych, które używa metody GetURLContentsAsync asynchronicznej. Zwróć uwagę, że jest ono silnie podobne do oryginalnego, synchronicznego rozwiązania.

' Add the following Imports statements, and add a reference for System.Net.Http.
Imports System.Net.Http
Imports System.Net
Imports System.IO

Class MainWindow

    Async Sub startButton_Click(sender As Object, e As RoutedEventArgs) Handles startButton.Click

        ' Disable the button until the operation is complete.
        startButton.IsEnabled = False

        resultsTextBox.Clear()

        '' One-step async call.
        Await SumPageSizesAsync()

        ' Two-step async call.
        'Dim sumTask As Task = SumPageSizesAsync()
        'Await sumTask

        resultsTextBox.Text &= vbCrLf & "Control returned to button1_Click."

        ' Reenable the button in case you want to run the operation again.
        startButton.IsEnabled = True
    End Sub

    Private Async Function SumPageSizesAsync() As Task

        ' Make a list of web addresses.
        Dim urlList As List(Of String) = SetUpURLList()

        Dim total = 0
        For Each url In urlList
            Dim urlContents As Byte() = Await GetURLContentsAsync(url)

            ' The previous line abbreviates the following two assignment statements.

            '//<snippet21>
            ' GetURLContentsAsync returns a task. At completion, the task
            ' produces a byte array.
            'Dim getContentsTask As Task(Of Byte()) = GetURLContentsAsync(url)
            'Dim urlContents As Byte() = Await getContentsTask

            DisplayResults(url, urlContents)

            ' Update the total.
            total += urlContents.Length
        Next

        ' Display the total count for all of the websites.
        resultsTextBox.Text &= String.Format(vbCrLf & vbCrLf &
                                             "Total bytes returned:  {0}" & vbCrLf, total)
    End Function

    Private Function SetUpURLList() As List(Of String)

        Dim urls = New List(Of String) From
            {
                "https://msdn.microsoft.com/library/windows/apps/br211380.aspx",
                "https://msdn.microsoft.com",
                "https://msdn.microsoft.com/library/hh290136.aspx",
                "https://msdn.microsoft.com/library/ee256749.aspx",
                "https://msdn.microsoft.com/library/hh290138.aspx",
                "https://msdn.microsoft.com/library/hh290140.aspx",
                "https://msdn.microsoft.com/library/dd470362.aspx",
                "https://msdn.microsoft.com/library/aa578028.aspx",
                "https://msdn.microsoft.com/library/ms404677.aspx",
                "https://msdn.microsoft.com/library/ff730837.aspx"
            }
        Return urls
    End Function

    Private Async Function GetURLContentsAsync(url As String) As Task(Of Byte())

        ' The downloaded resource ends up in the variable named content.
        Dim content = New MemoryStream()

        ' Initialize an HttpWebRequest for the current URL.
        Dim webReq = CType(WebRequest.Create(url), HttpWebRequest)

        ' Send the request to the Internet resource and wait for
        ' the response.
        Using response As WebResponse = Await webReq.GetResponseAsync()

            ' The previous statement abbreviates the following two statements.

            'Dim responseTask As Task(Of WebResponse) = webReq.GetResponseAsync()
            'Using response As WebResponse = Await responseTask

            ' Get the data stream that is associated with the specified URL.
            Using responseStream As Stream = response.GetResponseStream()
                ' Read the bytes in responseStream and copy them to content.
                Await responseStream.CopyToAsync(content)

                ' The previous statement abbreviates the following two statements.

                ' CopyToAsync returns a Task, not a Task<T>.
                'Dim copyTask As Task = responseStream.CopyToAsync(content)

                ' When copyTask is completed, content contains a copy of
                ' responseStream.
                'Await copyTask
            End Using
        End Using

        ' Return the result as a byte array.
        Return content.ToArray()
    End Function

    Private Sub DisplayResults(url As String, content As Byte())

        ' Display the length of each website. The string format
        ' is designed to be used with a monospaced font, such as
        ' Lucida Console or Global Monospace.
        Dim bytes = content.Length
        ' Strip off the "https://".
        Dim displayURL = url.Replace("https://", "")
        resultsTextBox.Text &= String.Format(vbCrLf & "{0,-58} {1,8}", displayURL, bytes)
    End Sub

End Class

Poniższy kod zawiera pełny przykład rozwiązania, które używa HttpClient metody GetByteArrayAsync .

' Add the following Imports statements, and add a reference for System.Net.Http.
Imports System.Net.Http
Imports System.Net
Imports System.IO

Class MainWindow

    Async Sub startButton_Click(sender As Object, e As RoutedEventArgs) Handles startButton.Click

        resultsTextBox.Clear()

        ' Disable the button until the operation is complete.
        startButton.IsEnabled = False

        ' One-step async call.
        Await SumPageSizesAsync()

        ' Two-step async call.
        'Dim sumTask As Task = SumPageSizesAsync()
        'Await sumTask

        resultsTextBox.Text &= vbCrLf & "Control returned to button1_Click."

        ' Reenable the button in case you want to run the operation again.
        startButton.IsEnabled = True
    End Sub

    Private Async Function SumPageSizesAsync() As Task

        ' Declare an HttpClient object and increase the buffer size. The
        ' default buffer size is 65,536.
        Dim client As HttpClient =
            New HttpClient() With {.MaxResponseContentBufferSize = 1000000}

        ' Make a list of web addresses.
        Dim urlList As List(Of String) = SetUpURLList()

        Dim total = 0
        For Each url In urlList
            ' GetByteArrayAsync returns a task. At completion, the task
            ' produces a byte array.
            Dim urlContents As Byte() = Await client.GetByteArrayAsync(url)

            ' The following two lines can replace the previous assignment statement.
            'Dim getContentsTask As Task(Of Byte()) = client.GetByteArrayAsync(url)
            'Dim urlContents As Byte() = Await getContentsTask

            DisplayResults(url, urlContents)

            ' Update the total.
            total += urlContents.Length
        Next

        ' Display the total count for all of the websites.
        resultsTextBox.Text &= String.Format(vbCrLf & vbCrLf &
                                             "Total bytes returned:  {0}" & vbCrLf, total)
    End Function

    Private Function SetUpURLList() As List(Of String)

        Dim urls = New List(Of String) From
            {
                "https://msdn.microsoft.com/library/windows/apps/br211380.aspx",
                "https://msdn.microsoft.com",
                "https://msdn.microsoft.com/library/hh290136.aspx",
                "https://msdn.microsoft.com/library/ee256749.aspx",
                "https://msdn.microsoft.com/library/hh290138.aspx",
                "https://msdn.microsoft.com/library/hh290140.aspx",
                "https://msdn.microsoft.com/library/dd470362.aspx",
                "https://msdn.microsoft.com/library/aa578028.aspx",
                "https://msdn.microsoft.com/library/ms404677.aspx",
                "https://msdn.microsoft.com/library/ff730837.aspx"
            }
        Return urls
    End Function

    Private Sub DisplayResults(url As String, content As Byte())

        ' Display the length of each website. The string format
        ' is designed to be used with a monospaced font, such as
        ' Lucida Console or Global Monospace.
        Dim bytes = content.Length
        ' Strip off the "https://".
        Dim displayURL = url.Replace("https://", "")
        resultsTextBox.Text &= String.Format(vbCrLf & "{0,-58} {1,8}", displayURL, bytes)
    End Sub

End Class

Zobacz też