Paginación con Azure SDK para .NET
En este artículo obtendrá información sobre cómo usar la funcionalidad de paginación de Azure SDK para .NET a fin de trabajar de forma eficiente y productiva con grandes conjuntos de datos. La paginación es el acto de dividir grandes conjuntos de datos en páginas, lo que facilita al consumidor iterar por cantidades de datos más pequeñas. A partir de C# 8, puede crear y consumir flujos de forma asincrónica mediante flujos asincrónicos. Los flujos asincrónicos se basan en la interfaz IAsyncEnumerable<T>. Azure SDK para .NET expone una implementación de IAsyncEnumerable<T>
con su clase AsyncPageable<T>
.
Todos los ejemplos de este artículo se basan en los siguientes paquetes NuGet:
- Azure.Security.KeyVault.Secrets
- Microsoft.Extensions.Azure
- Microsoft.Extensions.Hosting
- System.Linq.Async
Para obtener el directorio más reciente de paquetes de Azure SDK para .NET, vea Versiones más recientes de Azure SDK.
Tipos de valor devuelto paginables
Los clientes de los que se crea una instancia desde Azure SDK para .NET pueden devolver los siguientes tipos paginables.
Tipo | Descripción |
---|---|
Pageable<T> |
Colección de valores recuperados en páginas |
AsyncPageable<T> |
Colección de valores recuperados de forma asincrónica en páginas |
La mayoría de los ejemplos de este artículo son asincrónicos, con variaciones del tipo AsyncPageable<T>
. Es ideal usar la programación asincrónica para operaciones enlazadas a E/S. Un caso de uso perfecto es usar las API asincrónicas de Azure SDK para .NET, ya que estas operaciones representan llamadas de red HTTP/S.
Iteración por AsyncPageable
con await foreach
Para iterar por un elemento AsyncPageable<T>
con la sintaxis await foreach
, considere el ejemplo siguiente:
async Task IterateSecretsWithAwaitForeachAsync()
{
AsyncPageable<SecretProperties> allSecrets = client.GetPropertiesOfSecretsAsync();
await foreach (SecretProperties secret in allSecrets)
{
Console.WriteLine($"IterateSecretsWithAwaitForeachAsync: {secret.Name}");
}
}
En el código de C# anterior:
- Se invoca al método SecretClient.GetPropertiesOfSecretsAsync y se devuelve un objeto
AsyncPageable<SecretProperties>
. - En un bucle
await foreach
, cada elementoSecretProperties
se genera de forma asincrónica. - A medida que se materializa cada
secret
, se escribe suName
en la consola.
Iteración por AsyncPageable
con while
Para iterar por un objeto AsyncPageable<T>
cuando la sintaxis await foreach
no está disponible, use un bucle 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();
}
}
En el código de C# anterior:
- Se invoca el método SecretClient.GetPropertiesOfSecretsAsync y se devuelve un objeto
AsyncPageable<SecretProperties>
. - Se invoca el método AsyncPageable<T>.GetAsyncEnumerator y se devuelve un objeto
IAsyncEnumerator<SecretProperties>
. - El método MoveNextAsync() se invoca repetidamente hasta que no hay elementos que devolver.
Iteración por páginas AsyncPageable
Si quiere control sobre la recepción de páginas de valores del servicio, use el 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);
}
}
En el código de C# anterior:
- Se invoca al método SecretClient.GetPropertiesOfSecretsAsync y se devuelve un objeto
AsyncPageable<SecretProperties>
. - Se invoca al método AsyncPageable<T>.AsPages y se devuelve
IAsyncEnumerable<Page<SecretProperties>>
. - Se itera de forma asincrónica por cada página mediante
await foreach
. - Cada página tiene un conjunto de Page<T>.Values que representa una interfaz
IReadOnlyList<T>
que se itera con un bucleforeach
sincrónico. - Cada página también contiene un elemento Page<T>.ContinuationToken que se puede usar para solicitar la página siguiente.
Uso de System.Linq.Async
con AsyncPageable
El paquete System.Linq.Async
proporciona un conjunto de métodos LINQ que funcionan en el tipo IAsyncEnumerable<T>. Como AsyncPageable<T>
implementa IAsyncEnumerable<T>
, puede usar System.Linq.Async
para consultar y transformar los datos.
Conversión en List<T>
Use ToListAsync
para convertir un elemento AsyncPageable<T>
en un objeto List<T>
. Este método podría realizar varias llamadas de servicio si los datos no se devuelven en una sola página.
async Task ToListAsync()
{
AsyncPageable<SecretProperties> allSecrets =
client.GetPropertiesOfSecretsAsync();
List<SecretProperties> secretList = await allSecrets.ToListAsync();
secretList.ForEach(secret =>
Console.WriteLine($"ToListAsync: {secret.Name}"));
}
En el código de C# anterior:
- Se invoca al método SecretClient.GetPropertiesOfSecretsAsync y se devuelve un objeto
AsyncPageable<SecretProperties>
. - Se espera al método
ToListAsync
, que materializa una nueva instancia deList<SecretProperties>
.
Toma de los primeros N elementos
Take
se puede usar para obtener solo los primeros N
elementos del objeto AsyncPageable
. El uso de Take
realizará el menor número de llamadas de servicio necesarias para obtener los elementos 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}");
}
}
Más métodos
System.Linq.Async
ofrece otros métodos que proporcionan una funcionalidad equivalente a sus homólogos Enumerable
sincrónicos. Algunos ejemplos de estos métodos son Select
, Where
, OrderBy
y GroupBy
.
Atención a la evaluación del lado cliente
Al usar el paquete System.Linq.Async
, tenga en cuenta que las operaciones de LINQ se ejecutan en el cliente. La consulta siguiente capturaría todos los elementos solo para contarlos:
// ⚠️ DON'T DO THIS! 😲
int expensiveSecretCount =
await client.GetPropertiesOfSecretsAsync()
.CountAsync();
Advertencia
La misma advertencia se aplica a operadores como Where
. Siempre se prefiere el filtrado, la agregación o las proyecciones de datos del lado servidor si están disponibles.
Como una secuencia observable
El paquete System.Linq.Async
se usa principalmente para proporcionar funcionalidades de patrón de observador sobre secuencias IAsyncEnumerable<T>
. Los flujos asincrónicos se basan en la extracción. Mientras sus elementos se iteran, se extrae el siguiente elemento disponible. Este enfoque es el contrario al patrón de observador, que se basa en la incorporación. A medida que los elementos van estando disponibles, se insertan en los suscriptores que actúan como observadores. El paquete System.Linq.Async
proporciona el método de extensión ToObservable
, que permite convertir una interfaz IAsyncEnumerable<T>
en una instancia de IObservable<T>
.
Imagine una implementación 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}");
}
Podría consumir el método de extensión ToObservable
de la siguiente manera:
IDisposable UseTheToObservableMethod()
{
AsyncPageable<SecretProperties> allSecrets =
client.GetPropertiesOfSecretsAsync();
IObservable<SecretProperties> observable = allSecrets.ToObservable();
return observable.Subscribe(
new SecretPropertyObserver());
}
En el código de C# anterior:
- Se invoca al método SecretClient.GetPropertiesOfSecretsAsync y se devuelve un objeto
AsyncPageable<SecretProperties>
. - Se llama al método
ToObservable()
en la instancia deAsyncPageable<SecretProperties>
, y se devuelve una interfazIObservable<SecretProperties>
. - Se realiza la suscripción al objeto
observable
, se pasa la implementación del observador y se devuelve la suscripción al autor de la llamada. - La suscripción es un elemento
IDisposable
. Cuando se elimina, la suscripción finaliza.
Iteración por paginable
Pageable<T>
es una versión sincrónica de AsyncPageable<T>
que se puede usar con un bucle foreach
normal.
void IterateWithPageable()
{
Pageable<SecretProperties> allSecrets = client.GetPropertiesOfSecrets();
foreach (SecretProperties secret in allSecrets)
{
Console.WriteLine($"IterateWithPageable: {secret.Name}");
}
}
Importante
Aunque esta API sincrónica está disponible, para obtener una mejor experiencia, use las API asincrónicas alternativas.