Percorrer uma coleção usando os SDKs do Microsoft Graph

Por motivos de desempenho, coleções de entidades geralmente são divididas em páginas e cada página é retornada com uma URL para a próxima página. A classe PageIterator simplifica o consumo de coleções paginadas. O PageIterator lida com a enumeração da página atual e a solicitação de páginas subsequentes automaticamente.

Como alternativa, você pode usar a propriedade para solicitar manualmente as@odata.nextLink páginas subsequentes.

Cabeçalhos de solicitação

Se você enviar cabeçalhos de solicitação adicionais em sua solicitação inicial, esses cabeçalhos não serão incluídos por padrão nas solicitações de página subsequentes. Se esses cabeçalhos precisam ser enviados em solicitações subsequentes, você deve defini-los explicitamente.

Iterar em todas as mensagens

O exemplo a seguir mostra a iteração de todas as mensagens na caixa de correio de um usuário.

Dica

Este exemplo define um tamanho de página pequeno usando o top parâmetro para fins de demonstração. Você pode definir o tamanho da página até 999 para minimizar o número de solicitações necessárias.

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

Parar e retomar a iteração

Alguns cenários exigem a interrupção do processo de iteração para executar outras ações. É possível pausar a iteração retornando false do retorno de chamada da iteração. A iteração pode ser retomada chamando o resume método no 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();
}

Solicitando manualmente páginas subsequentes

Como alternativa ao uso da classe PageIterator, você pode marcar manualmente a resposta de uma @odata.nextLink propriedade e solicitar a próxima página.

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

Tratamento de erros

Evitando erros DirectoryPageTokenNotFoundException

Ao paginar por grandes conjuntos de dados, você pode encontrar o DirectoryPageTokenNotFoundException erro, o que impede que o aplicativo cliente recupere com êxito as páginas subsequentes. Esse erro ocorre quando o aplicativo cliente usa um token de uma operação de repetição para solicitar a próxima página de resultados.

Para evitar esse erro, não use tokens de operações de repetição para solicitações de página subsequentes, pois não há garantia de que esses tokens sejam válidos para solicitações futuras. Em vez disso, mantenha o token da última resposta bem-sucedida e use-o para a próxima solicitação de página. Portanto, o @odata.nextLink valor usado para a repetição deve ser usado para a solicitação de página subsequente.

Cenário de exemplo

  1. Recupere a Página 1 e receba um token "Token1".
  2. Use "Token1" para solicitar a Página 2.
  3. Se você encontrar um erro de rede, repita a solicitação.
  4. Durante a nova tentativa, você receberá um novo token "RetryToken".
  5. Não use "RetryToken" para solicitar a Página 3, pois isso pode causar o DirectoryPageTokenNotFoundException erro.
  6. Em vez disso, use "Token1" (o token da última resposta bem-sucedida de não repetição) para solicitar a Página 3.