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


Страница через коллекцию с помощью пакетов SDK Microsoft Graph

По соображениям производительности коллекции сущностей часто разбиваются на страницы, и каждая страница возвращается с URL-адресом следующей страницы. Класс PageIterator упрощает использование страничных коллекций. PageIterator обрабатывает перечисление текущей страницы и запрос последующих страниц автоматически.

Кроме того, можно использовать @odata.nextLink свойство для запроса последующих страниц вручную.

Заголовки запросов

Если вы отправляете дополнительные заголовки запросов в исходном запросе, эти заголовки не включаются по умолчанию в последующие запросы страницы. Если эти заголовки требуется отправлять в последующие запросы, их необходимо явно настроить.

Итерации по всем сообщениям

В следующем примере показано перебор всех сообщений в почтовом ящике пользователя.

Совет

В этом примере задается небольшой размер страницы с top помощью параметра для демонстрационных целей. Вы можете задать размер страницы до 999, чтобы свести к минимуму количество необходимых запросов.

var messages = await graphClient.Me.Messages
    .GetAsync(requestConfiguration =>
    {
        requestConfiguration.QueryParameters.Top = 10;
        requestConfiguration.QueryParameters.Select =
            ["sender", "subject", "body"];
        requestConfiguration.Headers.Add(
            "Prefer", "outlook.body-content-type=\"text\"");
    });

if (messages == null)
{
    return;
}

var pageIterator = PageIterator<Message, MessageCollectionResponse>
    .CreatePageIterator(
        graphClient,
        messages,
        // Callback executed for each item in
        // the collection
        (msg) =>
        {
            Console.WriteLine(msg.Subject);
            return true;
        },
        // Used to configure subsequent page
        // requests
        (req) =>
        {
            // Re-add the header to subsequent requests
            req.Headers.Add("Prefer", "outlook.body-content-type=\"text\"");
            return req;
        });

await pageIterator.IterateAsync();

Остановка и возобновление итерации

В некоторых сценариях для выполнения других действий требуется остановить процесс итерации. Можно приостановить итерацию, вернувшись false из обратного вызова итерации. Итерацию можно возобновить, вызвав resume метод в PageIterator.

int count = 0;
int pauseAfter = 25;

var messages = await graphClient.Me.Messages
    .GetAsync(requestConfiguration =>
    {
        requestConfiguration.QueryParameters.Top = 10;
        requestConfiguration.QueryParameters.Select =
            ["sender", "subject"];
    });

if (messages == null)
{
    return;
}

var pageIterator = PageIterator<Message, MessageCollectionResponse>
    .CreatePageIterator(
        graphClient,
        messages,
        (msg) =>
        {
            Console.WriteLine(msg.Subject);
            count++;
            // If we've iterated over the limit,
            // stop the iteration by returning false
            return count < pauseAfter;
        });

await pageIterator.IterateAsync();

while (pageIterator.State != PagingState.Complete)
{
    Console.WriteLine("Iteration paused for 5 seconds...");
    await Task.Delay(5000);
    // Reset count
    count = 0;
    await pageIterator.ResumeAsync();
}

Запрос последующих страниц вручную

В качестве альтернативы использованию класса PageIterator можно вручную проверка ответ для @odata.nextLink свойства и запросить следующую страницу.

var messages = await graphClient.Me.Messages
    .GetAsync(requestConfiguration =>
    {
        requestConfiguration.QueryParameters.Top = 10;
    });

while (messages?.Value != null)
{
    foreach (var message in messages.Value)
    {
        Console.WriteLine(message.Subject);
    }

    // If OdataNextLink has a value, there is another page
    if (!string.IsNullOrEmpty(messages.OdataNextLink))
    {
        // Pass the OdataNextLink to the WithUrl method
        // to request the next page
        messages = await graphClient.Me.Messages
            .WithUrl(messages.OdataNextLink)
            .GetAsync();
    }
    else
    {
        // No more results, exit loop
        break;
    }
}

Обработка ошибок

Предотвращение ошибок DirectoryPageTokenNotFoundException

При разбиении по страницам через большие наборы данных может возникнуть DirectoryPageTokenNotFoundException ошибка, которая не позволяет клиентскому приложению успешно получить последующие страницы. Эта ошибка возникает, когда клиентское приложение использует маркер из операции повтора для запроса следующей страницы результатов.

Чтобы избежать этой ошибки, не используйте маркеры из операций повторных попыток для последующих запросов страниц, так как эти маркеры не гарантируются для будущих запросов. Вместо этого сохраните маркер из последнего успешного ответа и используйте его для следующего запроса страницы. Таким образом @odata.nextLink , значение, используемое для повторных попыток, следует использовать для последующего запроса страницы.

Пример сценария

  1. Извлеките страницу 1 и получите маркер Token1.
  2. Используйте "Token1", чтобы запросить страницу 2.
  3. Если возникает ошибка сети, повторите запрос.
  4. Во время повторных попыток вы получите новый токен "RetryToken".
  5. Не используйте RetryToken для запроса страницы 3, так как это может вызвать ошибку DirectoryPageTokenNotFoundException .
  6. Вместо этого используйте "Token1" (токен из последнего успешного ответа без повторных попыток), чтобы запросить страницу 3.