Przewodnik: uzyskiwanie dostępu do sieci Web przy użyciu Async i Await (Visual Basic)

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

Aby uzyskać więcej informacji na temat funkcji asynchronicznej, zobacz Asynchroniczne programowanie za pomocą 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. Następnie przewodnik konwertuje aplikację na rozwiązanie asynchroniczne przy użyciu nowych funkcji.

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

W tym przewodniku wykonasz następujące zadania:

Zobacz sekcję Przykład , aby zapoznać się z kompletnym przykładem asynchronicznym.

Wymagania wstępne

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

Tworzenie aplikacji WPF

  1. Uruchom program Visual Studio.

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

    Zostanie otwarte okno dialogowe Nowy projekt .

  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ź ciąg AsyncExampleWPF, a następnie wybierz przycisk OK.

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

Projektowanie prostego systemu WPF MainWindow

  1. W edytorze programu 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.

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

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

    • Na karcie Tekst określ czcionkę monospacedową, 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.

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

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

    Aby uzyskać więcej informacji na temat 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ę Projekt, Dodaj odwołanie.

    Zostanie wyświetlone okno dialogowe Menedżer odwołań.

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

  4. W obszarze Zestawy wybierz pozycję Struktura, 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 Import

  1. W Eksplorator rozwiązań otwórz menu skrótów dla 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ć procedurę startButton_Click obsługi zdarzeń w MainWindow.xaml.vb.

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

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

    Kod wywołuje metodę, która napędza aplikację , SumPageSizesi wyświetla komunikat, gdy kontrolka powróci do startButton_Click.

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

    • SumPageSizes, który pobiera listę adresów URL stron internetowych z SetUpURLList , a następnie wywołuje GetURLContents i DisplayResults przetwarza każdy adres 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 programie startButton_Click obsługi zdarzeń w 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 liczby trwa kilka sekund. W tym czasie wątek interfejsu użytkownika jest blokowany podczas oczekiwania na pobranie żądanych zasobów. W związku z tym nie można przenosić, maksymalizować, zminimalizować ani nawet zamknąć okna wyświetlania po wybraniu przycisku Uruchom . Te działania kończą się niepowodzeniem, dopóki liczba bajtów nie zacznie się pojawiać. Jeśli witryna internetowa nie odpowiada, nie masz żadnych wskazówek, które witryny nie powiodły się. Trudno jest nawet przestać czekać i zamknąć program.

Konwertowanie metody GetURLContents na metodę asynchroniczną

  1. Aby przekonwertować rozwiązanie synchroniczne na rozwiązanie asynchroniczne, najlepszym miejscem do uruchomienia jest GetURLContents to, że wywołania HttpWebRequest.GetResponse metody i Stream.CopyTo metody to miejsce, w którym aplikacja uzyskuje dostęp do sieci Web. Program .NET Framework ułatwia konwersję, dostarczając asynchroniczne wersje obu metod.

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

    Uwaga

    Podczas opracowywania kroków opisanych w tym przewodniku pojawia się kilka błędów kompilatora. Możesz je zignorować i kontynuować z przewodnikiem.

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

    Using response As WebResponse = webReq.GetResponseAsync()
    
  2. GetResponseAsync zwraca wartość Task<TResult>. W tym przypadku zmienna zwracana przez zadanie , TResultma typ WebResponse. Zadanie jest obietnicą utworzenia rzeczywistego WebResponse obiektu po pobraniu żądanych danych, a zadanie zostało uruchomione do ukończenia.

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

    Using response As WebResponse = Await webReq.GetResponseAsync()
    

    Operator Await zawiesza wykonywanie bieżącej metody , GetURLContentsaż do ukończenia oczekiwanego zadania. W międzyczasie kontrolka powraca do obiektu wywołującego bieżącej metody. W tym przykładzie bieżąca metoda to GetURLContents, a obiekt wywołujący to SumPageSizes. Po zakończeniu zadania obiecany WebResponse obiekt jest generowany jako wartość oczekiwanego zadania i przypisany do zmiennej response.

    Poprzednie stwierdzenie można oddzielić od następujących dwóch stwierdzeń, aby wyjaśnić, co się stanie.

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

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

    Jeśli metoda asynchronizna ma pracę, która nie zależy od ukończenia zadania, metoda może kontynuować pracę między tymi dwiema instrukcjami, po wywołaniu metody asynchronicznej i przed zastosowaniem operatora await. Przykłady można znaleźć w temacie How to: Make Multiple Web Requests in Parallel by Using Async and Await (Visual Basic) and How to: Extend the Async Walkthrough by Using Task.WhenAll (Visual Basic) ( Porady: rozszerzanie przewodnika asynchronicznego przy użyciu funkcji Task.WhenAll (Visual Basic)).

  3. Ponieważ operator został dodany Await w poprzednim kroku, występuje błąd kompilatora. Operator może być używany tylko w metodach oznaczonych modyfikatorem Async . Ignoruj błąd podczas powtarzania kroków konwersji, aby zastąpić wywołanie CopyTo metody wywołaniem metody CopyToAsync.

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

    • Metoda CopyTo or CopyToAsync kopiuje bajty do argumentu content, i nie zwraca znaczącej wartości. W wersji synchronicznej wywołanie metody CopyTo to prosta instrukcja, która nie zwraca wartości. Wersja asynchroniczna , CopyToAsynczwraca wartość Task. Zadanie działa jak "Task(void)" i umożliwia oczekiwanie na metodę. Zastosuj Await metodę lub await do wywołania CopyToAsyncmetody , jak 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. Wszystko, co pozostało do zrobienia, GetURLContents to dostosowanie podpisu metody. Operator można używać Await tylko w metodach oznaczonych modyfikatorem Async . Dodaj modyfikator, aby oznaczyć metodę jako metodę asynchroniową, jak pokazano w poniższym kodzie.

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

    Aby uzyskać więcej informacji, zobacz Async Return Types (Visual Basic).

    Metoda GetURLContents ma instrukcję return, a instrukcja zwraca tablicę bajtów. W związku z tym zwracany typ wersji asynchronizowanej to Task(T), gdzie T jest tablicą bajtów. Wprowadź następujące zmiany w podpisie metody:

    • Zmień typ zwracany 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())
    

    Po wprowadzeniu tych kilku zmian konwersja GetURLContents metody asynchronicznej jest zakończona.

Konwertowanie sumPageSizes na metodę asynchroniczną

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

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

    • Zastosuj Await do zadania, które GetURLContentsAsync zwraca, aby uzyskać wartość 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. Wprowadź następujące zmiany w podpisie metody:

    • Oznacz metodę za pomocą Async modyfikatora.

    • Dodaj ciąg "Async" do nazwy metody.

    • Nie ma zmiennej zwracanej przez zadanie T, tym razem, ponieważ SumPageSizesAsync nie zwraca wartości T. (metoda nie Return ma instrukcji). Jednak metoda musi zwrócić wartość Task , aby można było oczekiwać. 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 na SumPageSizesSumPageSizesAsync jest zakończona.

Konwertowanie startButton_Click na metodę asynchroniczną

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

  2. Ponieważ SumPageSizesAsync jest metodą asynchroniową, zmień kod w procedurze obsługi zdarzeń, aby oczekiwać na wynik.

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

    Podobnie jak w poprzednich procedurach, można przekonwertować wywołanie 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 wprowadzeniu operacji, dodaj następującą instrukcję w górnej startButton_Click części, aby wyłączyć przycisk Uruchom .

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

    Można ponownie przywrócić przycisk na końcu programu obsługi zdarzeń.

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

    Aby uzyskać więcej informacji na temat ponownego uwierzytelniania, zobacz Obsługa ponownej reentrancy w aplikacjach asynchronicznych (Visual Basic).

  4. Na koniec dodaj Async modyfikator do deklaracji, aby program obsługi zdarzeń mógł 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 Task , ponieważ procedury obsługi zdarzeń muszą być Sub procedurami w Visual Basic.

    Konwersja projektu z synchronicznego na asynchroniczne przetwarzanie jest zakończona.

Testowanie rozwiązania asynchronicznego

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

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

    • Wyniki nie występują jednocześnie po zakończeniu przetwarzania. Na przykład oba programy zawierają wiersz, startButton_Click który czyści pole tekstowe. Intencją jest wyczyszczenie pola tekstowego między przebiegami po drugim wybraniu przycisku Start po pojawieniu się jednego zestawu wyników. W wersji synchronicznej pole tekstowe jest czyszczone tuż przed wyświetleniem liczników po raz drugi, po zakończeniu pobierania i wątku interfejsu użytkownika można wykonać inne czynności. W wersji asynchronicznej pole tekstowe jest czyszczane natychmiast po wybraniu przycisku Uruchom .

    • Co najważniejsze, wątek interfejsu użytkownika nie jest blokowany podczas pobierania. Okno można przenosić lub zmieniać rozmiar, gdy zasoby internetowe są pobierane, liczone i wyświetlane. 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

  1. Program .NET Framework udostępnia 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 jej użyć zamiast GetURLContentsAsync metody utworzonej we wcześniejszej procedurze.

    Pierwszym krokiem jest utworzenie HttpClient obiektu w metodzie SumPageSizesAsync . 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, zastąp wywołanie GetURLContentsAsync metody wywołaniem HttpClient metody .

    Dim urlContents As Byte() = Await client.GetByteArrayAsync(url)
    
  3. Usuń lub oznacz jako komentarz metodę GetURLContentsAsync , którą napisałeś.

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

    Zachowanie tej wersji projektu powinno być zgodne z zachowaniem, które opisano w procedurze "Aby przetestować rozwiązanie asynchroniczne", ale z jeszcze mniejszym nakładem pracy.

Przykład

Poniżej przedstawiono pełny przykład przekonwertowanego rozwiązania asynchronicznego korzystającego z metody asynchronicznej GetURLContentsAsync . Zwróć uwagę, że silnie przypomina oryginalne, synchroniczne rozwiązanie.

' 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ż