Chamar APIs assíncronas em C# ou Visual Basic

Windows inclui muitas APIs assíncronas para garantir que seu aplicativo permaneça responsivo quando ele funciona, o que pode levar um longo período de tempo. Este tópico discute como usar métodos assíncronos em C# ou Microsoft Visual Basic.

As APIs assíncronas evitam que seu aplicativo tenha que esperar a conclusão de operações longas antes de prosseguir com a execução. Por exemplo, um aplicativo que baixa informações da Internet pode passar vários segundos aguardando a chegada das informações. Se você usar um método síncrono para recuperar as informações, o aplicativo será bloqueado até que o método retorne. O aplicativo não responderá à interação do usuário e, como parece não responsivo, o usuário pode ficar frustrado. Ao fornecer APIs assíncronas, Windows ajuda a garantir que seu aplicativo permaneça responsivo ao usuário ao executar operações longas.

A maioria das APIs assíncronas no Windows não tem equivalentes síncronos, portanto, você precisa ter certeza de como usar as APIs assíncronas com C# ou Visual Basic em seu aplicativo Windows. Aqui, mostramos como chamar APIs assíncronas.

Usando APIs assíncronas

Por convenção, métodos assíncronos recebem nomes que terminam em "Async". Normalmente, você chama APIs assíncronas em resposta à ação de um usuário, como quando o usuário clica em um botão. Chamar um método assíncrono em um manipulador de eventos é uma das maneiras mais simples de usar APIs assíncronas. Aqui, usamos o operador await como exemplo.

Suponha que você tenha um aplicativo que lista os títulos de postagens de blog de um determinado local. O aplicativo tem um Botão que o usuário clica para obter os títulos. Os títulos são exibidos em um TextBlock. Quando o usuário clica no botão, é importante que o aplicativo permaneça responsivo enquanto aguarda as informações do site do blog. Para garantir essa capacidade de resposta, Windows fornece um método assíncrono, SyndicationClient.RetrieveFeedAsync, para baixar o feed.

O exemplo aqui obtém as listas de postagens de blog de um blog chamando o método assíncrono, SyndicationClient.RetrieveFeedAsync e aguardando 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á algumas coisas importantes sobre este exemplo. Primeiro, a linha SyndicationFeed feed = await client.RetrieveFeedAsync(feedUri) usa o operador await com a chamada para o método assíncrono, RetrieveFeedAsync. Você pode pensar no operador await como informando ao compilador que você está chamando um método assíncrono, o que faz com que o compilador faça algum trabalho extra para que você não precise. Em seguida, a declaração do manipulador de eventos inclui a palavra-chave assíncrona. Você deve incluir essa palavra-chave na declaração de método de qualquer método no qual use o operador await .

Neste tópico, não entraremos em muitos detalhes do que o compilador faz com o operador await , mas vamos examinar o que seu aplicativo faz para que ele seja assíncrono e responsivo. Considere o que acontece quando você usa código síncrono. Por exemplo, suponha que haja um método chamado SyndicationClient.RetrieveFeed síncrono. (Não existe esse método, mas imagine que existe.) Se o aplicativo incluísse a linha SyndicationFeed feed = client.RetrieveFeed(feedUri), em vez de SyndicationFeed feed = await client.RetrieveFeedAsync(feedUri), a execução do aplicativo pararia até que o valor retornado RetrieveFeed esteja disponível. E enquanto seu aplicativo aguarda a conclusão do método, ele não pode responder a nenhum outro evento, como outro evento click . Ou seja, seu aplicativo ficaria bloqueado até que RetrieveFeed retornasse.

Mas se você chamar client.RetrieveFeedAsync, o método iniciará a recuperação e retornará imediatamente. Quando você usa await com RetrieveFeedAsync, o aplicativo sai temporariamente do manipulador de eventos. Em seguida, ele pode processar outros eventos enquanto RetrieveFeedAsync é executado de forma assíncrona. Isso mantém o aplicativo responsivo ao usuário. Quando RetrieveFeedAsync é concluído e o SyndicationFeed está disponível, o aplicativo essencialmente reentra no manipulador de eventos de onde havia parado, após SyndicationFeed feed = await client.RetrieveFeedAsync(feedUri), e conclui o restante do método.

O interessante de usar o operador await é que o código não parece muito diferente da aparência do código se você usou o método imaginário RetrieveFeed . Há maneiras 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 de forma assíncrona. Isso torna o código assíncrono difícil de escrever, difícil de entender e difícil de manter. Usando o operador await , você obtém os benefícios de um aplicativo assíncrono sem tornar seu código complexo.

Retornar tipos e resultados de APIs assíncronas

Se você seguiu o link para RetrieveFeedAsync, talvez tenha notado que o tipo de retorno de RetrieveFeedAsync não é um SyndicationFeed. Em vez disso, o tipo de retorno é IAsyncOperationWithProgress<SyndicationFeed, RetrievalProgress>. Exibida a partir da sintaxe bruta, uma API assíncrona retorna um objeto que contém o resultado dentro dela. Embora seja comum, e às vezes útil, pensar em um método assíncrono como sendo aguardado, o operador await realmente opera no valor retornado do método, não no método. Quando você aplica o operador await , o que você recebe de volta é o resultado de chamar GetResult no objeto retornado pelo método. No exemplo, o SyndicationFeed é o resultado de RetrieveFeedAsync.GetResult().

Ao usar um método assíncrono, você pode examinar a assinatura para ver o que você receberá de volta depois de aguardar o valor retornado do método. Todas as APIs assíncronas retornam um dos seguintes tipos:

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

A tabela aqui fornece 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 IAsyncOperation<StorageFile> Arquivo de Armazenamento
XmlDocument.SaveToFileAsync IAsyncAction void
InkStrokeContainer.LoadAsync IAsyncActionWithProgress<UInt64> void
DataReader.LoadAsync DataReaderLoadOperation, uma classe de resultados personalizada que implementa o IAsyncOperation<UInt32> UInt32

Note

FileOpenPicker e outras APIs de seletor exigem a inicialização do identificador de janela (HWND) em aplicativos WinUI 3 para desktop. Antes de chamar PickSingleFileAsync, chame WinRT.Interop.InitializeWithWindow.Initialize(picker, hwnd), em que hwnd vem de WindowNative.GetWindowHandle(this). Consulte Exibir APIs do seletor do WinUI 3 que exigem um identificador de janela (HWND).

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

Tratamento de erros

Ao usar o operador await para recuperar seus resultados de um método assíncrono, você pode usar um bloco try/catch para lidar com erros que ocorrem em métodos assíncronos, assim como você faz para métodos síncronos. O exemplo anterior encapsula o método RetrieveFeedAsync e aguarda a operação em um bloco try/catch para lidar com erros quando uma exceção é gerada.

Quando métodos assíncronos chamam outros métodos assíncronos, qualquer método assíncrono que resulta em uma exceção será propagado para os métodos externos. Isso significa que você pode colocar um bloco try/catch no método mais externo para capturar erros dos métodos assíncronos aninhados. Novamente, isso é semelhante a como você captura exceções para métodos síncronos. No entanto, você não pode usar await no bloco catch .

Tip

A partir do C# 6.0 (.NET Framework 4.6/Visual Studio 2015), você pode usar await no bloco catch.

Resumo e próximas etapas

O padrão de chamar um método assíncrono que mostramos aqui é o mais simples a ser usado quando você chama APIs assíncronas em um manipulador de eventos. Você também pode usar esse padrão ao chamar um método assíncrono em um método substituído que retorna void ou sub in Visual Basic.

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

  • Por convenção, métodos assíncronos recebem nomes que terminam em "Async".
  • Qualquer método que use o operador await deve ter sua declaração marcada com a palavra-chave assíncrona .
  • Quando um aplicativo encontra o operador await , o aplicativo permanece responsivo à interação do usuário enquanto o método assíncrono é executado.
  • Aguardar o valor retornado por um método assíncrono retorna um objeto que contém o resultado. Na maioria dos casos, o resultado contido no valor retornado é o que é útil, não o valor retornado em si. Você pode encontrar o tipo do valor contido dentro do resultado examinando o tipo de retorno do método assíncrono.
  • O uso de APIs assíncronas e padrões assíncronos geralmente é uma maneira de melhorar a capacidade de resposta do seu aplicativo.

O exemplo neste tópico gera um texto semelhante 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