Chamar APIs assíncronas em C# ou Visual Basic

O Windows inclui muitas APIs assíncronas para garantir que a sua aplicação se mantém responsiva quando trabalha, o que pode demorar muito tempo. Este tópico discute como usar métodos assíncronos em C# ou Microsoft Visual Basic.

APIs assíncronas impedem que a sua aplicação espere que grandes operações sejam concluídas antes de continuar a execução. Por exemplo, uma aplicação que descarrega informações da Internet pode passar vários segundos à espera que a informação chegue. Se usares um método síncrono para recuperar a informação, a aplicação fica bloqueada até o método voltar. A aplicação não responde à interação do utilizador e, como parece não responder, o utilizador pode ficar frustrado. Ao fornecer APIs assíncronas, o Windows ajuda a garantir que a sua aplicação se mantém responsiva ao utilizador durante operações longas.

A maioria das APIs assíncronas no Windows não tem equivalentes síncronas, por isso tens de ter a certeza de que percebes como usar as APIs assíncronas com C# ou Visual Basic na tua aplicação para Windows. Aqui mostramos como chamar APIs assíncronas.

Utilização de APIs assíncronas

Por convenção, os métodos assíncronos recebem nomes que terminam em "Assíncrono". Normalmente, chama-se APIs assíncronas em resposta à ação do utilizador, como quando o utilizador clica num botão. Chamar um método assíncrono num gestor de eventos é uma das formas mais simples de usar APIs assíncronas. Aqui usamos o operador await como exemplo.

Suponha que tem uma aplicação que lista os títulos dos artigos de blogue de um determinado local. A aplicação tem um botão que o utilizador clica para obter os títulos. Os títulos são exibidos num TextBlock. Quando o utilizador clica no botão, é importante que a aplicação se mantenha responsiva enquanto espera pela informação do site do blog. Para garantir esta capacidade de resposta, o Windows disponibiliza um método assíncrono, SyndicationClient.RetrieveFeedAsync, para descarregar o feed.

O exemplo aqui obtém as listas de publicações de um blogue ao chamar o método assíncrono, SyndicationClient.RetrieveFeedAsync, e aguardar o resultado.

// Put the keyword async on the declaration of the event handler.
private async void Button_Click_1(object sender, RoutedEventArgs e)
{

    Windows.Web.Syndication.SyndicationClient client = new SyndicationClient();

    Uri feedUri
        = new Uri("http://windowsteamblog.com/windows/b/windowsexperience/atom.aspx");

    try
    {
        SyndicationFeed feed = await client.RetrieveFeedAsync(feedUri);

        // The rest of this method executes after await RetrieveFeedAsync completes.
        rssOutput.Text = feed.Title.Text + Environment.NewLine;

        foreach (SyndicationItem item in feed.Items)
        {
            rssOutput.Text += item.Title.Text + ", " +
                             item.PublishedDate.ToString() + Environment.NewLine;
        }
    }
    catch (Exception ex)
    {
        // Log Error.
        rssOutput.Text =
            "I'm sorry, but I couldn't load the page," +
            " possibly due to network problems." +
            "Here's the error message I received: "
            + ex.ToString();
    }
}
' Put the keyword Async on the declaration of the event handler.
Private Async Sub Button_Click_1(sender As Object, e As RoutedEventArgs)
    Dim client As New Windows.Web.Syndication.SyndicationClient()
    Dim feedUri As New Uri("http://windowsteamblog.com/windows/b/windowsexperience/atom.aspx")

    Try
        Dim feed As SyndicationFeed = Await client.RetrieveFeedAsync(feedUri)

        ' The rest of this method executes after the await operation completes.
        rssOutput.Text = feed.Title.Text & vbCrLf

        For Each item In feed.Items
            rssOutput.Text += $"{item.Title.Text}, {item.PublishedDate.ToString()}{vbCrLf}"
        Next

    Catch ex As Exception
        ' Log Error.
        rssOutput.Text = "I'm sorry, but I couldn't load the page," &
                         " possibly due to network problems." &
                         "Here's the error message I received: " &
                          ex.ToString()
    End Try

End Sub

Há alguns aspetos importantes neste exemplo. Primeiro, a linha SyndicationFeed feed = await client.RetrieveFeedAsync(feedUri) usa o operador await com a chamada para o método assíncrono, RetrieveFeedAsync. Podes pensar no operador await como dizer ao compilador que estás a chamar um método assíncrono, o que faz com que o compilador faça algum trabalho extra para que tu não tenhas de o fazer. De seguida, a declaração do gestor de eventos inclui a palavra-chave assíncrona. Deve incluir esta palavra-chave na declaração de método de qualquer método em que utilize o operador await .

Neste tópico, não vamos entrar em muitos detalhes sobre o que o compilador faz com o operador await , mas vamos analisar o que a sua aplicação faz para que seja assíncrona e responsiva. Considera o que acontece quando usas código síncrono. Por exemplo, suponha que existe um método chamado SyndicationClient.RetrieveFeed que é síncrono. (Não existe tal método, mas imagine que existe.) Se a sua aplicação incluísse a linha SyndicationFeed feed = client.RetrieveFeed(feedUri), em vez de SyndicationFeed feed = await client.RetrieveFeedAsync(feedUri), a execução da aplicação pararia até que o valor de retorno de RetrieveFeed esteja disponível. E enquanto a sua aplicação espera que o método seja concluído, não consegue responder a outros eventos, como outro evento Click . Ou seja, a tua aplicação ficaria bloqueada até RetrieveFeed regressar.

Mas se chamar client.RetrieveFeedAsync, o método inicia a recuperação e retorna imediatamente. Quando usas await com o RetrieveFeedAsync, a aplicação sai temporariamente do gestor de eventos. Depois, pode processar outros eventos enquanto o RetrieveFeedAsync é executado de forma assíncrona. Isto mantém a aplicação responsiva ao utilizador. Quando RetrieveFeedAsync é concluído e o SyndicationFeed está disponível, a aplicação basicamente volta a entrar no processador de eventos no ponto em que tinha ficado, após SyndicationFeed feed = await client.RetrieveFeedAsync(feedUri), e termina o restante do método.

O bom de usar o operador await é que o código não parece muito diferente de como se usasse o método imaginário RetrieveFeed . Existem formas de escrever código assíncrono em C# ou Visual Basic sem o operador await, mas o código resultante tende a enfatizar a mecânica de execução assíncrona. Isto torna o código assíncrono difícil de escrever, difícil de entender e difícil de manter. Ao usar o operador await , obtém os benefícios de uma aplicação assíncrona sem tornar o seu código complexo.

Tipos de retorno e resultados de APIs assíncronas

Se seguiu o link para RetrieveFeedAsync, poderá ter reparado que o tipo de retorno de RetrieveFeedAsync não é um SyndicationFeed. Em vez disso, o tipo de retorno é IAsyncOperationWithProgress<SyndicationFeed, RetrievalProgress>. Vista a partir da sintaxe bruta, uma API assíncrona devolve um objeto que contém o resultado dentro de si. Embora seja comum, e por vezes útil, pensar num método assíncrono como sendo aguardável, o operador await opera na verdade com base no valor de retorno do método, e não no próprio método. Quando aplicas o operador await , o que obténs de volta é o resultado de chamar GetResult no objeto devolvido pelo método. No exemplo, o SyndicationFeed é o resultado de RetrieveFeedAsync.GetResult().

Quando usas um método assíncrono, podes examinar a assinatura para ver o que vais receber depois de aguardares o valor devolvido pelo método. Todas as APIs assíncronas retornam um dos seguintes tipos:

O tipo de resultado de um método assíncrono é o mesmo do TResult parâmetro tipo. Tipos sem um TResult não têm resultado. Podes pensar no resultado como nulo. No Visual Basic, um procedimento Sub é equivalente a um método com um tipo de retorno void.

A tabela aqui apresenta exemplos de métodos assíncronos e lista o tipo de retorno e o tipo de resultado de cada um.

Método assíncrono Tipo de retorno Tipo de resultado
SyndicationClient.RetrieveFeedAsync IAsyncOperationWithProgress<SyndicationFeed, RetrievalProgress> SyndicationFeed
FileOpenPicker.PickSingleFileAsync Ficheiro de Armazenamento IAsyncOperation<> Arquivo de Armazenamento
XmlDocument.SaveToFileAsync IAsyncAction Vazio
InkStrokeContainer.LoadAsync IAsyncActionWithProgress<UInt64> Vazio
DataReader.LoadAsync DataReaderLoadOperation, uma classe de resultados personalizada que implementa IAsyncOperation<UInt32> UInt32

Observação

FileOpenPicker e outras APIs do seletor requerem a inicialização do identificador de janela (HWND) em aplicações de ambiente de trabalho do WinUI 3. Antes de chamar PickSingleFileAsync, chame WinRT.Interop.InitializeWithWindow.Initialize(picker, hwnd), em que hwnd provém de WindowNative.GetWindowHandle(this). Veja as APIs do seletor de ecrã do WinUI 3 que requerem um identificador de janela (HWND).

Os métodos assíncronos definidos em aplicações .NET para Windows têm o tipo de retorno Tarefa ou Tarefa<TResult>. Os métodos que retornam Tarefa são semelhantes aos métodos assíncronos que devolvem IAsyncAction. Em cada caso, o resultado do método assíncrono é nulo. O tipo de retorno Task<TResult> é semelhante a IAsyncOperation<TResult>, na medida em que o resultado do método assíncrono quando a tarefa é executada é do mesmo tipo que o parâmetro de tipo TResult.

Tratamento de erros

Quando usa o operador await para obter os seus resultados de um método assíncrono, pode usar um bloco try/catch para lidar com erros que ocorrem em métodos assíncronos, tal como faz com métodos síncronos. O exemplo anterior envolve o método RetrieveFeedAsync e a operação await num bloco try/catch para lidar com erros quando uma exceção é lançada.

Quando métodos assíncronos chamam outros métodos assíncronos, qualquer método assíncrono que resulte numa exceção será propagado para os métodos externos. Isto significa que pode colocar um bloco try/catch no método mais externo para capturar erros dos métodos assíncronos aninhados. Mais uma vez, isto é semelhante à forma como se apanham exceções para métodos síncronos. No entanto, não é possível usar await no bloco catch.

Tip

A partir do C# 6.0 (.NET Framework 4.6 / Visual Studio 2015), podes usar await no bloco de captura.

Resumo e próximos passos

O padrão de chamar um método assíncrono que aqui mostramos é o mais simples de usar quando se chamam APIs assíncronas num gestor de eventos. Também pode usar este padrão quando chama um método assíncrono num método substituído que retorna void ou um Sub no Visual Basic.

Ao encontrar métodos assíncronos, é importante lembrar:

  • Por convenção, os métodos assíncronos recebem nomes que terminam em "Assíncrono".
  • Qualquer método que utilize o operador await deve ter a sua declaração marcada com a palavra-chave assíncrona .
  • Quando uma aplicação encontra o operador await , mantém-se responsiva à interação do utilizador enquanto o método assíncrono é executado.
  • Aguardar o valor devolvido por um método assíncrono retorna um objeto que contém o resultado. Na maioria dos casos, o resultado contido no valor de retorno é o que é útil, não o valor de retorno em si. Pode encontrar o tipo do valor contido no resultado olhando para o tipo de retorno do método assíncrono.
  • Usar APIs assíncronas e padrões assíncronos é frequentemente uma forma de melhorar a capacidade de resposta da sua aplicação.

O exemplo neste tópico gera texto que se assemelha a este.

Windows Experience Blog
PC Snapshot: Sony VAIO Y, 8/9/2011 10:26:56 AM -07:00
Tech Tuesday Live Twitter #Chat: Too Much Tech #win7tech, 8/8/2011 12:48:26 PM -07:00
Windows 7 themes: what's new and what's popular!, 8/4/2011 11:56:28 AM -07:00
PC Snapshot: Toshiba Satellite A665 3D, 8/2/2011 8:59:15 AM -07:00
Time for new school supplies? Find back-to-school deals on Windows 7 PCs and Office 2010, 8/1/2011 2:14:40 PM -07:00
Best PCs for blogging (or working) on the go, 8/1/2011 10:08:14 AM -07:00
Tech Tuesday – Blogging Tips and Tricks–#win7tech, 8/1/2011 9:35:54 AM -07:00
PC Snapshot: Lenovo IdeaPad U460, 7/29/2011 9:23:05 AM -07:00
GIVEAWAY: Survive BlogHer with a Sony VAIO SA and a Samsung Focus, 7/28/2011 7:27:14 AM -07:00
3 Ways to Stay Cool This Summer, 7/26/2011 4:58:23 PM -07:00
Getting RAW support in Photo Gallery & Windows 7 (…and a contest!), 7/26/2011 10:40:51 AM -07:00
Tech Tuesdays Live Twitter Chats: Photography Tips, Tricks and Essentials, 7/25/2011 12:33:06 PM -07:00
3 Tips to Go Green With Your PC, 7/22/2011 9:19:43 AM -07:00
How to: Buy a Green PC, 7/22/2011 9:13:22 AM -07:00
Windows 7 themes: the distinctive artwork of Cheng Ling, 7/20/2011 9:53:07 AM -07:00