Compartilhar via


Paginação com o SDK do Azure para .NET

Neste artigo, você aprenderá a usar a funcionalidade de paginação do SDK do Azure para .NET a fim trabalhar de maneira eficiente e produtiva com conjuntos de dados grandes. A paginação é o ato de dividir grandes conjuntos de dados em páginas, facilitando para o consumidor iterar por meio de volumes menores de dados. A partir do C# 8, você pode criar e consumir fluxos de maneira assíncrona usando os fluxos assíncronos. Os fluxos assíncronos são baseados na interface IAsyncEnumerable<T>. O SDK do Azure para .NET expõe uma implementação de IAsyncEnumerable<T> com a classe AsyncPageable<T>.

Todos os exemplos deste artigo dependem dos seguintes pacotes NuGet:

Para ver o diretório mais recente do SDK do Azure para pacotes .NET, confira as últimas versões do SDK do Azure.

Tipos de retorno pagináveis

As instâncias de clientes criadas por meio do SDK do Azure para .NET podem retornar os tipos pagináveis a seguir.

Tipo Descrição
Pageable<T> Uma coleção de valores recuperados em páginas
AsyncPageable<T> Uma coleção de valores recuperados de maneira assíncrona em páginas

A maioria dos exemplos deste artigo é assíncrona, usando variações do tipo AsyncPageable<T>. O uso da programação assíncrona para operações associadas a E/S é ideal. Um caso de uso perfeito é usar as APIs assíncronas do SDK do Azure para .NET, pois essas operações representam chamadas de rede HTTP/S.

Iterar em AsyncPageable com await foreach

Para iterar em um AsyncPageable<T> usando a sintaxe await foreach, considere o seguinte exemplo:

async Task IterateSecretsWithAwaitForeachAsync()
{
    AsyncPageable<SecretProperties> allSecrets = client.GetPropertiesOfSecretsAsync();

    await foreach (SecretProperties secret in allSecrets)
    {
        Console.WriteLine($"IterateSecretsWithAwaitForeachAsync: {secret.Name}");
    }
}

No código anterior do C#:

  • O método SecretClient.GetPropertiesOfSecretsAsync é invocado e retorna um objeto AsyncPageable<SecretProperties>.
  • Em um loop await foreach, cada SecretProperties é gerada de maneira assíncrona.
  • Conforme cada secret é materializado, o Name dele é gravado no console.

Iterar em AsyncPageable com while

Para iterar em um AsyncPageable<T> quando a sintaxe await foreach não está disponível, use um loop while.

async Task IterateSecretsWithWhileLoopAsync()
{
    AsyncPageable<SecretProperties> allSecrets = client.GetPropertiesOfSecretsAsync();

    IAsyncEnumerator<SecretProperties> enumerator = allSecrets.GetAsyncEnumerator();
    try
    {
        while (await enumerator.MoveNextAsync())
        {
            SecretProperties secret = enumerator.Current;
            Console.WriteLine($"IterateSecretsWithWhileLoopAsync: {secret.Name}");
        }
    }
    finally
    {
        await enumerator.DisposeAsync();
    }
}

No código anterior do C#:

Iterar em páginas AsyncPageable

Caso deseje controlar o recebimento de páginas de valores do serviço, use o método AsyncPageable<T>.AsPages:

async Task IterateSecretsAsPagesAsync()
{
    AsyncPageable<SecretProperties> allSecrets = client.GetPropertiesOfSecretsAsync();

    await foreach (Page<SecretProperties> page in allSecrets.AsPages())
    {
        foreach (SecretProperties secret in page.Values)
        {
            Console.WriteLine($"IterateSecretsAsPagesAsync: {secret.Name}");
        }

        // The continuation token that can be used in AsPages call to resume enumeration
        Console.WriteLine(page.ContinuationToken);
    }
}

No código anterior do C#:

  • O método SecretClient.GetPropertiesOfSecretsAsync é invocado e retorna um objeto AsyncPageable<SecretProperties>.
  • O método AsyncPageable<T>.AsPages é invocado e retorna um IAsyncEnumerable<Page<SecretProperties>>.
  • Cada página é iterada de maneira assíncrona, usando await foreach.
  • Cada página tem um conjunto de Page<T>.Values, que representa um IReadOnlyList<T> que é iterado com um foreach síncrono.
  • Cada página também contém um Page<T>.ContinuationToken, que pode ser usado para solicitar a próxima página.

Usar System.Linq.Async com AsyncPageable

O pacote System.Linq.Async fornece um conjunto de métodos LINQ que operam no tipo IAsyncEnumerable<T>. Como AsyncPageable<T> implementa IAsyncEnumerable<T>, você pode usar System.Linq.Async para consultar e transformar os dados.

Conversão em um List<T>

Use ToListAsync para converter uma AsyncPageable<T> em uma List<T>. Esse método poderá fazer várias chamadas de serviço se os dados não forem retornados em uma só página.

async Task ToListAsync()
{
    AsyncPageable<SecretProperties> allSecrets =
        client.GetPropertiesOfSecretsAsync();

    List<SecretProperties> secretList = await allSecrets.ToListAsync();

    secretList.ForEach(secret =>
        Console.WriteLine($"ToListAsync: {secret.Name}"));
}

No código anterior do C#:

  • O método SecretClient.GetPropertiesOfSecretsAsync é invocado e retorna um objeto AsyncPageable<SecretProperties>.
  • O método ToListAsync é aguardado, o que materializa uma nova instância de List<SecretProperties>.

Usar os primeiros N elementos

Take pode ser usado para obter apenas os primeiros elementos N do AsyncPageable. O uso de Take fará o menor número de chamadas de serviço necessárias para obter itens N.

async Task TakeAsync(int count = 30)
{
    AsyncPageable<SecretProperties> allSecrets =
        client.GetPropertiesOfSecretsAsync();

    await foreach (SecretProperties secret in allSecrets.Take(count))
    {
        Console.WriteLine($"TakeAsync: {secret.Name}");
    }
}

Mais métodos

System.Linq.Async fornece outros métodos que fornecem funcionalidade equivalente aos Enumerableequivalentes síncronos. Entre os exemplos desses métodos estão Select, Where, OrderBy e GroupBy.

Cuidado com a avaliação do lado do cliente

Ao usar o pacote System.Linq.Async, tenha cuidado para que as operações LINQ sejam executadas no cliente. A seguinte consulta busca todos os itens apenas para contá-los:

// ⚠️ DON'T DO THIS! 😲
int expensiveSecretCount =
    await client.GetPropertiesOfSecretsAsync()
        .CountAsync();

Aviso

O mesmo aviso se aplica a operadores como Where. Sempre prefira a filtragem do lado do servidor, a agregação ou as projeções de dados, se disponível.

Como uma sequência observável

O pacote System.Linq.Async é usado principalmente para fornecer funcionalidades de padrão de observador em sequências IAsyncEnumerable<T>. Os fluxos assíncronos são baseados em pull. À medida que os itens são iterados, o próximo item disponível é extraído. Essa abordagem está em justaposição com o padrão de observador, que é baseado em push. À medida que os itens ficam disponíveis, eles são enviados por push para os assinantes que funcionam como observadores. O pacote System.Linq.Async fornece o método de extensão ToObservable que permite converter um IAsyncEnumerable<T> em um IObservable<T>.

Imagine uma implementação de IObserver<SecretProperties>:

sealed file class SecretPropertyObserver : IObserver<SecretProperties>
{
    public void OnCompleted() =>
        Console.WriteLine("Done observing secrets");

    public void OnError(Exception error) =>
        Console.WriteLine($"Error observing secrets: {error}");

    public void OnNext(SecretProperties secret) =>
        Console.WriteLine($"Observable: {secret.Name}");
}

Você pode consumir o método de extensão ToObservable da seguinte maneira:

IDisposable UseTheToObservableMethod()
{
    AsyncPageable<SecretProperties> allSecrets =
        client.GetPropertiesOfSecretsAsync();

    IObservable<SecretProperties> observable = allSecrets.ToObservable();

    return observable.Subscribe(
        new SecretPropertyObserver());
}

No código anterior do C#:

  • O método SecretClient.GetPropertiesOfSecretsAsync é invocado e retorna um objeto AsyncPageable<SecretProperties>.
  • O método ToObservable() é chamado na instância AsyncPageable<SecretProperties>, retornando um IObservable<SecretProperties>.
  • O observable é assinado, transmitindo a implementação do observador e retornando a assinatura para o chamador.
  • A assinatura é um IDisposable. Quando ele é descartado, a assinatura termina.

Iteração em pagináveis

Pageable<T> é uma versão síncrona de AsyncPageable<T> que pode ser usada com um loop foreach normal.

void IterateWithPageable()
{
    Pageable<SecretProperties> allSecrets = client.GetPropertiesOfSecrets();

    foreach (SecretProperties secret in allSecrets)
    {
        Console.WriteLine($"IterateWithPageable: {secret.Name}");
    }
}

Importante

Embora essa API síncrona esteja disponível, use as alternativas de API assíncrona para ter uma experiência melhor.

Confira também