Search code examples
c#microsoft-graph-apimicrosoft-graph-sdks

MS Graph v5.42.0: Changing page size when paging messages


I use paging to get messages with MS Graph v5.42.0. In the below c# example I want to get 50 messages from a mail folder that contains 70 messages. The first page returns 30 messages as expected. For the second page I change the page size to 20 (Top). But it seems that changing the page size has no influence when getting the second page because 30 messages are returned. Is changing the page size not possible when using paging?

int maxItemSize = 50;
int pageSize = 30;
if (maxItemSize <= pageSize)
    pageSize = maxItemSize;

string itemSearchFilter = GetItemFilters(messageClasses, onlyMailsWithAttachments,
    ignoredDomains, archiveSize, archiveDate, archiveAge, setFilterIgnoreSignedItems, setFilterNotKdxArchived, setFilterKdxArchived);

string expandValue = string.Format("singleValueExtendedProperties($filter = id eq '{0}' or id eq '{1}' or id eq '{2}' or id eq '{3}' or id eq '{4}')",
    MessageClassPropertyID1, DisplayToPropertyID1, DisplayCcPropertyID1, NativeBodyPropertyID, MessageSizePropertyID1);

List<Message> messages = new List<Message>();

var messagesResponse = await GraphServiceClient
    .Users[CurrentMailBoxAddress]
    .MailFolders[FolderId]
    .Messages
    .GetAsync((requestConfiguration) =>
    {
        requestConfiguration.QueryParameters.Top = pageSize;
        requestConfiguration.QueryParameters.Expand = new string[] { expandValue };
        requestConfiguration.QueryParameters.Filter = itemSearchFilter;
    });

while (messagesResponse.Value != null)
{
    messages.AddRange(messagesResponse.Value);

    if (messages.Count() >= maxItemSize)
        break;
    else
    {
        int messagesToBeRetrieved = maxItemSize - messages.Count();
        if (messagesToBeRetrieved <= pageSize)
        {
            // Resets the page size for the last request
            pageSize = messagesToBeRetrieved;
        }

        // If OdataNextLink has a value, there is another page
        if (!string.IsNullOrEmpty(messagesResponse.OdataNextLink))
        {
            messagesResponse = await GraphServiceClient
                .Users[CurrentMailBoxAddress]
                .MailFolders[FolderId]
                .Messages
                .WithUrl(messagesResponse.OdataNextLink)
                .GetAsync((requestConfiguration) =>
                {
                    requestConfiguration.QueryParameters.Top = pageSize;
                    requestConfiguration.QueryParameters.Expand = new string[] { expandValue };
                    requestConfiguration.QueryParameters.Filter = itemSearchFilter;
                });
        }
        else
        {
            // No more results, exit loop
            break;
        }
    }
}

Solution

  • As the comment of the method WithUrl says

    Using this method means any other path or query parameters are ignored.

    It means that every query parameter specified in GetAsync(...) is ignored.

    OdataNextLink contains the query parameters specified in the first request with extra parameter $skip

    https://graph.microsoft.com/v1.0/users/{user_id}/mailFolders/{folder_id}/messages?$filter=xxx&$expand=xxx&$top=30&$skip=30
    

    Based on this I would get rid of WithUrl and specify all query parameters manually for the next requests

    int maxItemSize = 50;
    int pageSize = 30;
    // how many items should be skipped
    int skipItems = 0;
    if (maxItemSize <= pageSize)
        pageSize = maxItemSize;
    
    string itemSearchFilter = GetItemFilters(messageClasses, onlyMailsWithAttachments,
        ignoredDomains, archiveSize, archiveDate, archiveAge, setFilterIgnoreSignedItems, setFilterNotKdxArchived, setFilterKdxArchived);
    
    string expandValue = string.Format("singleValueExtendedProperties($filter = id eq '{0}' or id eq '{1}' or id eq '{2}' or id eq '{3}' or id eq '{4}')",
        MessageClassPropertyID1, DisplayToPropertyID1, DisplayCcPropertyID1, NativeBodyPropertyID, MessageSizePropertyID1);
    
    List<Message> messages = new List<Message>();
    
    var messagesResponse = await GraphServiceClient
        .Users[CurrentMailBoxAddress]
        .MailFolders[FolderId]
        .Messages
        .GetAsync((requestConfiguration) =>
        {
            requestConfiguration.QueryParameters.Top = pageSize;
            requestConfiguration.QueryParameters.Expand = new string[] { expandValue };
            requestConfiguration.QueryParameters.Filter = itemSearchFilter;
        });
    
    while (messagesResponse.Value != null)
    {
        messages.AddRange(messagesResponse.Value);
    
        if (messages.Count() >= maxItemSize)
            break;
        else
        {
            int messagesToBeRetrieved = maxItemSize - messages.Count();
            if (messagesToBeRetrieved <= pageSize)
            {
                // increment number of items to be skipped
                skipItems += pageSize;
                // Resets the page size for the last request
                pageSize = messagesToBeRetrieved;
            }
    
            // If OdataNextLink has a value, there is another page
            if (!string.IsNullOrEmpty(messagesResponse.OdataNextLink))
            {
                messagesResponse = await GraphServiceClient
                    .Users[CurrentMailBoxAddress]
                    .MailFolders[FolderId]
                    .Messages
                    // WithUrl removed
                    .GetAsync((requestConfiguration) =>
                    {
                        // specify skip parameter
                        requestConfiguration.QueryParameters.Skip = skipItems;
                        requestConfiguration.QueryParameters.Top = pageSize;
                        requestConfiguration.QueryParameters.Expand = new string[] { expandValue };
                        requestConfiguration.QueryParameters.Filter = itemSearchFilter;
                    });
            }
            else
            {
                // No more results, exit loop
                break;
            }
        }
    }