Passo a passo: Acessando a Web usando Async e Await (Visual Basic)

Você pode escrever programas assíncronos de forma mais fácil e intuitiva usando os recursos async/await. Você pode escrever código assíncrono que se parece com código síncrono e deixar o compilador lidar com as difíceis funções de retorno de chamada e continuações que o código assíncrono geralmente implica.

Para obter mais informações sobre o recurso Async, consulte Programação assíncrona com Async e Await (Visual Basic).

Este passo a passo começa com um aplicativo síncrono do Windows Presentation Foundation (WPF) que soma o número de bytes em uma lista de sites. Em seguida, o passo a passo converte o aplicativo em uma solução assíncrona usando os novos recursos.

Você pode desenvolver os aplicativos concluindo o passo a passo ou baixando o exemplo do Navegador de Exemplo .NET. O código de exemplo está no projeto SerialAsyncExample .

Neste passo a passo, você conclui as seguintes tarefas:

Consulte a seção Exemplo para obter o exemplo assíncrono completo.

Pré-requisitos

O Visual Studio 2012 ou posterior deve ser instalado no seu computador. Para obter mais informações, consulte a página Downloads do Visual Studio.

Criar uma aplicação WPF

  1. Inicie o Visual Studio.

  2. Na barra de menus, escolha Arquivo, Novo, Projeto.

    A caixa de diálogo Novo projeto é aberta.

  3. No painel Modelos Instalados, escolha Visual Basic e, em seguida, escolha Aplicativo WPF na lista de tipos de projeto.

  4. Na caixa de texto Nome, digite AsyncExampleWPFe escolha o botão OK.

    O novo projeto aparece no Gerenciador de Soluções.

Projete um WPF MainWindow simples

  1. No Editor de Códigos do Visual Studio, escolha a guia MainWindow.xaml .

  2. Se a janela Caixa de Ferramentas não estiver visível, abra o menu Exibir e escolha Caixa de Ferramentas.

  3. Adicione um controle Button e um controle TextBox à janela MainWindow .

  4. Realce o controle TextBox e, na janela Properties , defina os seguintes valores:

    • Defina a propriedade Name como resultsTextBox.

    • Defina a propriedade Height como 250.

    • Defina a propriedade Width como 500.

    • Na guia Texto, especifique uma fonte monoespaçada, como Lucida Console ou Global Monospace.

  5. Realce o controle Button e, na janela Propriedades, defina os seguintes valores:

    • Defina a propriedade Name como startButton.

    • Altere o valor da propriedade Content de Button para Start.

  6. Posicione a caixa de texto e o botão para que ambos apareçam na janela MainWindow .

    Para obter mais informações sobre o WPF XAML Designer, consulte Criando uma interface do usuário usando o Designer XAML.

Adicionar uma referência

  1. No Gerenciador de Soluções, realce o nome do seu projeto.

  2. Na barra de menus, escolha Projeto, Adicionar referência.

    A caixa de diálogo Gerenciador de Referência é exibida.

  3. Na parte superior da caixa de diálogo, verifique se seu projeto está direcionado ao .NET Framework 4.5 ou superior.

  4. Na área Assemblies, escolha Framework se ainda não estiver escolhida.

  5. Na lista de nomes, marque a caixa de seleção System.Net.Http .

  6. Escolha o botão OK para fechar a caixa de diálogo.

Adicionar instruções Import necessárias

  1. No Gerenciador de Soluções, abra o menu de atalho para MainWindow.xaml.vb e escolha Exibir Código.

  2. Adicione as instruções a seguir Imports na parte superior do arquivo de código, se elas ainda não estiverem presentes.

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

Criar um aplicativo síncrono

  1. Na janela de design, MainWindow.xaml, clique duas vezes no botão Iniciar para criar o startButton_Click manipulador de eventos no MainWindow.xaml.vb.

  2. No MainWindow.xaml.vb, copie o seguinte código no corpo de startButton_Click:

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

    O código chama o método que conduz o aplicativo SumPageSizese exibe uma mensagem quando o controle retorna para startButton_Click.

  3. O código para a solução síncrona contém os seguintes quatro métodos:

    • SumPageSizes, que obtém uma lista de URLs de páginas da Web e, em SetUpURLList seguida, chama GetURLContents e DisplayResults processa cada URL.

    • SetUpURLList, que cria e devolve uma lista de endereços Web.

    • GetURLContents, que baixa o conteúdo de cada site e retorna o conteúdo como uma matriz de bytes.

    • DisplayResults, que exibe o número de bytes na matriz de bytes para cada URL.

    Copie os quatro métodos a seguir e cole-os no manipulador de startButton_Click eventos em 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
    

Testar a solução síncrona

  1. Escolha a tecla F5 para executar o programa e, em seguida, escolha o botão Iniciar .

    Saída semelhante à seguinte lista deve aparecer:

    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.
    

    Observe que leva alguns segundos para exibir as contagens. Durante esse tempo, o thread da interface do usuário é bloqueado enquanto aguarda o download dos recursos solicitados. Como resultado, você não pode mover, maximizar, minimizar ou até mesmo fechar a janela de exibição depois de escolher o botão Iniciar . Esses esforços falham até que as contagens de bytes comecem a aparecer. Se um site não estiver respondendo, você não terá nenhuma indicação de qual site falhou. É difícil até parar de esperar e fechar o programa.

Converter GetURLContents em um método assíncrono

  1. Para converter a solução síncrona em uma solução assíncrona, o melhor lugar para começar é porque GetURLContents as chamadas para o HttpWebRequest.GetResponse método e para o Stream.CopyTo método são onde o aplicativo acessa a Web. O .NET Framework facilita a conversão fornecendo versões assíncronas de ambos os métodos.

    Para obter mais informações sobre os métodos usados no GetURLContents, consulte WebRequest.

    Nota

    À medida que você segue as etapas neste passo a passo, vários erros do compilador aparecem. Você pode ignorá-los e continuar com o passo a passo.

    Altere o método chamado na terceira linha de GetURLContents de de GetResponse para o método assíncrono baseado em GetResponseAsync tarefas.

    Using response As WebResponse = webReq.GetResponseAsync()
    
  2. GetResponseAsync retorna um Task<TResult>arquivo . Nesse caso, a variável de retorno da tarefa, TResult, tem o tipo WebResponse. A tarefa é uma promessa de produzir um objeto real WebResponse depois que os dados solicitados foram baixados e a tarefa foi executada até a conclusão.

    Para recuperar o WebResponse valor da tarefa, aplique um operador Await à chamada para GetResponseAsync, como mostra o código a seguir.

    Using response As WebResponse = Await webReq.GetResponseAsync()
    

    O Await operador suspende a execução do método atual, GetURLContents, até que a tarefa aguardada seja concluída. Enquanto isso, o controle retorna ao chamador do método atual. Neste exemplo, o método atual é GetURLContents, e o chamador é SumPageSizes. Quando a tarefa é concluída, o objeto prometido WebResponse é produzido como o valor da tarefa esperada e atribuído à variável response.

    A declaração anterior pode ser separada nas duas declarações seguintes para esclarecer o que acontece.

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

    A chamada para webReq.GetResponseAsync retornar um Task(Of WebResponse) ou Task<WebResponse>. Em seguida, um Await operador é aplicado à tarefa para recuperar o WebResponse valor.

    Se o seu método assíncrono tiver trabalho a fazer que não dependa da conclusão da tarefa, o método pode continuar com esse trabalho entre essas duas instruções, após a chamada para o método assíncrono e antes que o operador await seja aplicado. Para obter exemplos, consulte Como fazer várias solicitações da Web em paralelo usando Async e Await (Visual Basic) e Como estender o passo a passo assíncrono usando Task.WhenAll (Visual Basic).

  3. Como você adicionou o Await operador na etapa anterior, ocorre um erro de compilador. O operador só pode ser usado em métodos marcados com o modificador Assíncrono. Ignore o erro enquanto repete as etapas de conversão para substituir a chamada para CopyTo por uma chamada para CopyToAsync.

    • Altere o nome do método chamado para CopyToAsync.

    • O CopyTo método or copia CopyToAsync bytes para seu argumento contente não retorna um valor significativo. Na versão síncrona, a chamada para CopyTo é uma instrução simples que não retorna um valor. A versão assíncrona, CopyToAsync, retorna um Taskarquivo . A tarefa funciona como "Task(void)" e permite que o método seja aguardado. Aplique Await ou await à chamada para CopyToAsync, como mostra o código a seguir.

      Await responseStream.CopyToAsync(content)
      

      A instrução anterior abrevia as duas linhas de código a seguir.

      ' 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. Tudo o que falta fazer GetURLContents é ajustar a assinatura do método. Você pode usar o Await operador somente em métodos marcados com o modificador Assíncrono. Adicione o modificador para marcar o método como um método assíncrono, como mostra o código a seguir.

    Private Async Function GetURLContents(url As String) As Byte()
    
  5. O tipo de retorno de um método assíncrono só pode ser Task, Task<TResult>. No Visual Basic, o método deve ser um Function que retorna um Task ou um Task(Of T), ou o método deve ser um Sub. Normalmente, um Sub método é usado somente em um manipulador de eventos assíncrono, onde Sub é necessário. Em outros casos, você usa Task(T) se o método completed tem uma instrução Return que retorna um valor do tipo T e usa Task se o método completed não retorna um valor significativo.

    Para obter mais informações, consulte Tipos de retorno assíncronos (Visual Basic).

    Método GetURLContents tem uma instrução return, e a instrução retorna uma matriz de bytes. Portanto, o tipo de retorno da versão assíncrona é Task(T), onde T é uma matriz de bytes. Faça as seguintes alterações na assinatura do método:

    • Altere o tipo de retorno para Task(Of Byte()).

    • Por convenção, os métodos assíncronos têm nomes que terminam em "Async", portanto, renomeie o método GetURLContentsAsync.

    O código a seguir mostra essas alterações.

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

    Com essas poucas alterações, a conversão para GetURLContents um método assíncrono é concluída.

Converter SumPageSizes em um método assíncrono

  1. Repita as etapas do procedimento anterior para SumPageSizes. Primeiro, altere a chamada para GetURLContents uma chamada assíncrona.

    • Altere o nome do método chamado de GetURLContents para GetURLContentsAsync, se ainda não tiver feito isso.

    • Aplique Await à tarefa que GetURLContentsAsync retorna para obter o valor da matriz de bytes.

    O código a seguir mostra essas alterações.

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

    A atribuição anterior abrevia as duas linhas de código a seguir.

    ' 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. Faça as seguintes alterações na assinatura do método:

    • Marque o método com o Async modificador.

    • Adicione "Async" ao nome do método.

    • Não há nenhuma variável de retorno de tarefa, T, desta vez porque SumPageSizesAsync não retorna um valor para T. (O método não tem nenhuma Return instrução.) No entanto, o método deve retornar um Task para ser aguardado. Portanto, altere o tipo de método de Sub para Function. O tipo de retorno da função é Task.

    O código a seguir mostra essas alterações.

    Private Async Function SumPageSizesAsync() As Task
    

    A conversão de SumPageSizes para SumPageSizesAsync está completa.

Converter startButton_Click em um método assíncrono

  1. No manipulador de eventos, altere o nome do método chamado de SumPageSizes para SumPageSizesAsync, se ainda não tiver feito isso.

  2. Como SumPageSizesAsync é um método assíncrono, altere o código no manipulador de eventos para aguardar o resultado.

    A chamada para SumPageSizesAsync espelha a chamada para CopyToAsync em GetURLContentsAsync. A chamada retorna um Task, não um Task(T)arquivo .

    Como nos procedimentos anteriores, você pode converter a chamada usando uma instrução ou duas instruções. O código a seguir mostra essas alterações.

    ' One-step async call.
    Await SumPageSizesAsync()
    
    ' Two-step async call.
    Dim sumTask As Task = SumPageSizesAsync()
    Await sumTask
    
  3. Para evitar reentrar acidentalmente na operação, adicione a seguinte instrução na parte superior do startButton_Click para desativar o botão Iniciar .

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

    Você pode reativar o botão no final do manipulador de eventos.

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

    Para obter mais informações sobre reentrancy, consulte Manipulando reentrância em aplicativos assíncronos (Visual Basic).

  4. Finalmente, adicione o Async modificador à declaração para que o manipulador de eventos possa aguardar SumPagSizesAsync.

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

    Normalmente, os nomes dos manipuladores de eventos não são alterados. O tipo de retorno não é alterado para Task porque os manipuladores de eventos devem ser Sub procedimentos no Visual Basic.

    A conversão do projeto de processamento síncrono para assíncrono está concluída.

Testar a solução assíncrona

  1. Escolha a tecla F5 para executar o programa e, em seguida, escolha o botão Iniciar .

  2. A saída que se assemelha à saída da solução síncrona deve aparecer. No entanto, observe as seguintes diferenças.

    • Os resultados não ocorrem todos ao mesmo tempo, após a conclusão do processamento. Por exemplo, ambos os programas contêm uma linha que startButton_Click limpa a caixa de texto. A intenção é limpar a caixa de texto entre as execuções se você escolher o botão Iniciar pela segunda vez, depois que um conjunto de resultados tiver aparecido. Na versão síncrona, a caixa de texto é desmarcada pouco antes das contagens aparecerem pela segunda vez, quando os downloads são concluídos e o thread da interface do usuário está livre para fazer outro trabalho. Na versão assíncrona, a caixa de texto é limpa imediatamente após você escolher o botão Iniciar .

    • Mais importante ainda, o thread da interface do usuário não é bloqueado durante os downloads. Você pode mover ou redimensionar a janela enquanto os recursos da Web estão sendo baixados, contados e exibidos. Se um dos sites estiver lento ou não estiver respondendo, você pode cancelar a operação escolhendo o botão Fechar (o x no campo vermelho no canto superior direito).

Substitua o método GetURLContentsAsync por um método .NET Framework

  1. O .NET Framework fornece muitos métodos assíncronos que você pode usar. Um deles, o HttpClient.GetByteArrayAsync(String) método, faz exatamente o que você precisa para este passo a passo. Você pode usá-lo em vez do GetURLContentsAsync método que você criou em um procedimento anterior.

    A primeira etapa é criar um HttpClient objeto no SumPageSizesAsync método. Adicione a seguinte declaração no início do método.

    ' 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. No SumPageSizesAsync, substitua a chamada para o GetURLContentsAsync seu método por uma chamada para o HttpClient método.

    Dim urlContents As Byte() = Await client.GetByteArrayAsync(url)
    
  3. Remova ou comente o GetURLContentsAsync método que você escreveu.

  4. Escolha a tecla F5 para executar o programa e, em seguida, escolha o botão Iniciar .

    O comportamento desta versão do projeto deve corresponder ao comportamento descrito no procedimento "Para testar a solução assíncrona", mas com ainda menos esforço da sua parte.

Exemplo

A seguir está o exemplo completo da solução assíncrona convertida que usa o método assíncrono GetURLContentsAsync . Observe que ele se assemelha fortemente à solução original e síncrona.

' 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

O código a seguir contém o exemplo completo da solução que usa o HttpClient método, 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

Consulte também