Share via


Paginazione con Azure SDK per .NET

Questo articolo illustra come usare la funzionalità di paginazione di Azure SDK per .NET in modo efficiente e produttivo con set di dati di grandi dimensioni. La funzionalità di paginazione è l'atto di dividere set di dati di grandi dimensioni in pagine, semplificando l'iterazione da parte del consumer tramite quantità ridotte di dati. A partire da C# 8, è possibile creare e utilizzare i flussi in modo asincrono tramite flussi (asinc) asincroni. I flussi asincroni si basano sull'interfaccia IAsyncEnumerable<T>. Azure SDK per .NET espone un'implementazione di IAsyncEnumerable<T> con la relativa classe AsyncPageable<T>.

Tutti gli esempi in questo articolo si basano sui pacchetti NuGet seguenti:

Per la directory più recente dei pacchetti di Azure SDK per .NET, vedere Versioni più recenti di Azure SDK.

Tipi restituiti sottoponibili a paginazione

I client di cui è stata creata un'istanza da Azure SDK per .NET possono restituire i tipi sottoponibili a paginazione seguenti.

Tipo Descrizione
Pageable<T> Una raccolta di valori recuperati nelle pagine
AsyncPageable<T> Raccolta di valori recuperati in modo asincrono nelle pagine

La maggior parte degli esempi in questo articolo è asincrona, con le varianti del tipo AsyncPageable<T> in uso. L'uso della programmazione asincrona per le operazioni associate a I/O è ideale. Un caso d'uso perfetto usa le API asincrone di Azure SDK per .NET perché queste operazioni rappresentano chiamate di rete HTTP/S.

Eseguire l'iterazione di AsyncPageable con await foreach

Per eseguire l'iterazione di un oggetto AsyncPageable<T> usando la sintassi await foreach, considerare l'esempio seguente:

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

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

Nel codice C# precedente:

  • Il metodo SecretClient.GetPropertiesOfSecretsAsync viene richiamato e restituisce un oggetto AsyncPageable<SecretProperties>.
  • In un ciclo await foreach, ogni SecretProperties viene sospeso in modo asincrono.
  • Ogni volta in cui un oggetto secret viene materializzato, il relativo Name viene scritto nella console.

Eseguire l'iterazione di AsyncPageable con while

Per eseguire l'iterazione di un oggetto AsyncPageable<T> quando la sintassi await foreach non è disponibile, usare un ciclo 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();
    }
}

Nel codice C# precedente:

Eseguire l'iterazione su pagine AsyncPageable

Se si vuole controllare la ricezione di pagine di valori dal servizio, usare il metodo 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);
    }
}

Nel codice C# precedente:

  • Il metodo SecretClient.GetPropertiesOfSecretsAsync viene richiamato e restituisce un oggetto AsyncPageable<SecretProperties>.
  • Il metodo AsyncPageable<T>.AsPages viene richiamato e restituisce un elemento IAsyncEnumerable<Page<SecretProperties>>.
  • Viene eseguita l'iterazione di ogni pagina in modo asincrono usando await foreach.
  • Ogni pagina ha un set di Page<T>.Values, che rappresenta un oggetto IReadOnlyList<T> di cui è stata eseguita l'iterazione con un oggetto sincrono foreach.
  • Ogni pagina contiene anche un oggetto Page<T>.ContinuationToken, che può essere usato per richiedere la pagina successiva.

Usare System.Linq.Async con AsyncPageable

Il pacchetto System.Linq.Async fornisce un set di metodi LINQ che operano sul tipo IAsyncEnumerable<T>. Dato che AsyncPageable<T> implementa IAsyncEnumerable<T>, è possibile usare System.Linq.Async per eseguire query e trasformare i dati.

Convertire in un elemento List<T>

Usare ToListAsync per convertire un oggetto AsyncPageable<T> in un elemento List<T>. Questo metodo potrebbe effettuare diverse chiamate al servizio se i dati non vengono restituiti in una singola pagina.

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

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

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

Nel codice C# precedente:

  • Il metodo SecretClient.GetPropertiesOfSecretsAsync viene richiamato e restituisce un oggetto AsyncPageable<SecretProperties>.
  • Si attende che il metodo ToListAsync materializzi una nuova istanza List<SecretProperties>.

Considerare i primi N elementi

Take può essere usato per ottenere solo i primi N elementi dell'oggetto AsyncPageable. L'uso di Take consentirà di eseguire il minor numero di chiamate di servizio necessarie per ottenere N elementi.

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

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

Altri metodi

System.Linq.Async offre altri metodi che forniscono funzionalità equivalenti alle Enumerablecontroparti sincrone. Esempi di tali metodi sono Select, Where, OrderBy e GroupBy.

Attenzione alla valutazione lato client

Quando si usa il pacchetto System.Linq.Async, tenere presente che le operazioni LINQ vengono eseguite nel client. La query seguente recupera tutti gli elementi solo per conteggiarli:

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

Avviso

Lo stesso avviso si applica agli operatori come Where. Preferire sempre filtri lato server, aggregazione o proiezioni di dati, se disponibili.

Come sequenza osservabile

Il pacchetto System.Linq.Async viene usato principalmente per fornire funzionalità del criterio osservatore sulle sequenze IAsyncEnumerable<T>. I flussi asincroni sono basati sul pull. A mano a mano che si esegue l'iterazione degli elementi, viene eseguito il pull dell'elemento disponibile successivo. Questo approccio è in sovrapposizione con il modello osservatore, che è basato su push. A mano a mano che gli elementi diventano disponibili, viene eseguito il push ai sottoscrittori che fungono da osservatori. Il pacchetto System.Linq.Async fornisce il metodo di estensione ToObservable, che consente di convertire un oggetto IAsyncEnumerable<T> in un elemento IObservable<T>.

Immaginare un'implementazione di 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}");
}

È possibile utilizzare il metodo ToObservable di estensione come indicato di seguito:

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

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

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

Nel codice C# precedente:

  • Il metodo SecretClient.GetPropertiesOfSecretsAsync viene richiamato e restituisce un oggetto AsyncPageable<SecretProperties>.
  • Il metodo ToObservable() viene chiamato nell'istanza AsyncPageable<SecretProperties>, restituendo un oggetto IObservable<SecretProperties>.
  • Viene eseguita la sottoscrizione a observable, passando l'implementazione dell'osservatore, restituendo la sottoscrizione al chiamante.
  • La sottoscrizione è un elemento IDisposable. Quando viene eliminato, la sottoscrizione termina.

Eseguire l'iterazione su tipi sottoponibili a paginazione

Pageable<T> è una versione sincrona di AsyncPageable<T>, che può essere usata con un ciclo foreach normale.

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

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

Importante

Anche se questa API sincrona è disponibile, usare le API asincrone alternative per un'esperienza migliore.

Vedi anche