使用 Microsoft Graph SDK 分页浏览集合

出于性能原因,实体集合通常拆分为多个页面,并且每个页面都返回下一页的 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 来暂停迭代。 通过在 PageIterator 上调用 resume 方法,可以恢复迭代。

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