Compartir a través de


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:

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 elemento SecretProperties se genera de forma asincrónica.
  • A medida que se materializa cada secret, se escribe su Name 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:

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 bucle foreach 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 de List<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 de AsyncPageable<SecretProperties>, y se devuelve una interfaz IObservable<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.

Vea también