Поделиться через


Пагинация с Azure SDK для .NET

В этой статье вы узнаете, как использовать функциональность пагинации в пакете SDK Azure для .NET для эффективной и продуктивной работы с большими наборами данных. Разбиение на страницы — это процесс деления больших наборов данных на страницы, что позволяет пользователю проще работать с меньшим объемом данных. Начиная с C# 8, можно создавать и использовать потоки асинхронно с помощью асинхронных (асинхронных) потоков. Асинхронные потоки основаны на интерфейсе IAsyncEnumerable<T> . Пакет SDK Azure для .NET предоставляет реализацию IAsyncEnumerable<T> при помощи класса AsyncPageable<T>.

Все примеры из этой статьи основаны на следующих пакетах NuGet:

Последний каталог пакетов Azure SDK для .NET см. в последних выпусках пакета Azure SDK.

Типы возвращаемых объектов с пагинацией

Клиенты, созданные с использованием Azure SDK для .NET, могут возвращать следующие страницируемые типы данных.

Тип Описание
Pageable<T> Коллекция значений, полученных на страницах
AsyncPageable<T> Коллекция значений, асинхронно извлекаемых на страницах

Большинство примеров в этой статье являются асинхронными, используя варианты AsyncPageable<T> типа. Использование асинхронного программирования для операций с привязкой ввода-вывода идеально подходит. Идеальный вариант использования — использование асинхронных API из пакета SDK Azure для .NET, так как эти операции представляют сетевые вызовы HTTP/S.

Итерировать по AsyncPageable с помощью await foreach

Чтобы выполнить итерацию по AsyncPageable<T> с использованием синтаксиса await foreach, рассмотрим следующий пример:

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

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

В приведенном выше коде C#:

  • Метод SecretClient.GetPropertiesOfSecretsAsync вызывается и возвращает AsyncPageable<SecretProperties> объект.
  • В цикле await foreach каждый элемент SecretProperties асинхронно передается.
  • Когда каждый secret материализуется, его Name записывается в консоль.

Итерировать по AsyncPageable с помощью while

Чтобы выполнить итерацию по AsyncPageable<T>, когда синтаксис await foreach недоступен, используйте цикл while.

{
    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();
    }
}

В приведенном выше коде C#:

Итерируйте по AsyncPageable страницам

Если вы хотите контролировать получение страниц значений из службы, используйте метод AsyncPageable<T>.AsPages:

{
    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);
    }
}

В приведенном выше коде C#:

  • Метод SecretClient.GetPropertiesOfSecretsAsync вызывается и возвращает AsyncPageable<SecretProperties> объект.
  • Метод AsyncPageable<T>.AsPages вызывается и возвращается IAsyncEnumerable<Page<SecretProperties>>.
  • Каждая страница проходит итерацию асинхронно, используя await foreach.
  • Каждая страница содержит набор Page<T>.Values, представляющий IReadOnlyList<T>, над которым выполняется синхронная итерация с помощью foreach.
  • Каждая страница также содержит объект Page<T>.ContinuationToken, который можно использовать для запроса следующей страницы.

Используйте System.Linq.Async с AsyncPageable

Пакет System.Linq.Async предоставляет набор методов LINQ , работающих с IAsyncEnumerable<T> типом. Так как AsyncPageable<T> реализуется IAsyncEnumerable<T>, можно использовать System.Linq.Async для запроса и преобразования данных.

Конвертировать в List<T>

Используйте ToListAsync для преобразования AsyncPageable<T> в List<T>. Этот метод может вызывать несколько вызовов служб, если данные не возвращаются на одной странице.

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

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

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

В приведенном выше коде C#:

  • Метод SecretClient.GetPropertiesOfSecretsAsync вызывается и возвращает AsyncPageable<SecretProperties> объект.
  • Ожидается метод ToListAsync, который создает новый экземпляр List<SecretProperties>.

Возьмите первые N-элементы

Take можно использовать для получения только первых N элементов из AsyncPageable. Использование Take потребует минимальное количество вызовов службы для получения N элементов.

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

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

Дополнительные методы

System.Linq.Async предоставляет другие методы, которые предоставляют функциональные возможности, эквивалентные их синхронным Enumerable аналогам. Примеры таких методов: Select, Whereи OrderByGroupBy.

Осторожно: вычисления на клиентской стороне

При использовании System.Linq.Async пакета убедитесь, что операции LINQ выполняются на клиенте. Следующий запрос будет получить все элементы только для их подсчета:

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

Предупреждение

Такое же предупреждение применяется к операторам, таким как Where. Всегда предпочитайте фильтрацию на стороне сервера, агрегирование или проекции данных, если они доступны.

Как наблюдаемая последовательность

Пакет System.Linq.Async в основном используется для предоставления возможностей шаблона наблюдателя для IAsyncEnumerable<T> последовательностей. Асинхронные потоки работают по принципу вытягивания. По мере итерации элементов следующий доступный элемент извлекается. Этот подход находится в противопоставлении с шаблоном наблюдателя, который использует технологию push. По мере того как элементы становятся доступными, они передаются подписчикам, которые действуют как наблюдатели. Пакет System.Linq.Async предоставляет метод расширения ToObservable, который позволяет преобразовать IAsyncEnumerable<T> в IObservable<T>.

Представьте реализацию 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}");
}

Можно использовать метод расширения ToObservable следующим образом:

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

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

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

В приведенном выше коде C#:

  • Метод SecretClient.GetPropertiesOfSecretsAsync вызывается и возвращает AsyncPageable<SecretProperties> объект.
  • Метод ToObservable() вызывается в экземпляре AsyncPageable<SecretProperties> , возвращая объект IObservable<SecretProperties>.
  • На observable оформляется подписка, передаётся реализация наблюдателя, и эта подписка возвращается вызывающей стороне.
  • Подписка — это IDisposable. После удаления подписка заканчивается.

Итерации по страницам

Pageable<T> — синхронная версия AsyncPageable<T> , которую можно использовать с обычным foreach циклом.

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

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

Это важно

Хотя этот синхронный API доступен, используйте асинхронные альтернативные варианты API для лучшего взаимодействия.

См. также