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:
- Azure.Security.KeyVault.Secrets
- Microsoft.Extensions.Azure
- Microsoft.Extensions.Hosting
- System.Linq.Async
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
, cadaSecretProperties
é gerada de maneira assíncrona. - Conforme cada
secret
é materializado, oName
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#:
- O método SecretClient.GetPropertiesOfSecretsAsync é invocado e retorna um objeto
AsyncPageable<SecretProperties>
. - O método AsyncPageable<T>.GetAsyncEnumerator é invocado, retornando um
IAsyncEnumerator<SecretProperties>
. - O método MoveNextAsync() é invocado repetidamente até que não haja itens a serem retornados.
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 umforeach
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 deList<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 Enumerable
equivalentes 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ânciaAsyncPageable<SecretProperties>
, retornando umIObservable<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.