2

I am using Microsoft Graph SDK to create a batch request that contains individual requests to request 20 different users. When I call GetNextLinkAsync() the result is always null. I have tried requesting 1000 different users using batch requests each containing 20 individual requests. This works fine, response is always returned in a single batch response.

  1. I couldn't understand why the response is returned in single batch response content rather than giving me the link to fetch the next response?
  2. Even though next link is null always, how can I follow it using Graph SDK? It is a string. It's not like next page request.
foreach (var batchRequest in batchRequests)
            {
                try
                {
                    var responses = await PostBatchRequest(batchRequest.Request);
                    foreach (var id in batchRequest.RequestIds)
                    {
                        try
                        {
                            var user = await responses.GetResponseByIdAsync<User>(id);
                            users.Add(user.UserPrincipalName, user.Id);

                        } catch (ServiceException e)
                        {
                            logger.LogInformation(e.StatusCode);
                        }
                    }
                } catch (ServiceException e)
                {
                    logger.LogInformation(e.StatusCode);
                }
            }

I couldn't find proper documentation that tells you how to follow next link using Graph SDK or why it is always null for this type of requests, or are there any special type of requests for which next link is returned?

GMDev
  • 97
  • 1
  • 13

1 Answers1

4

So a lot of this is framework stuff that's inside my wrapper classes, but the crux of the solution to your issue should be inside here:

var results = await batch.ParseAsync<ContactFolderContactsCollectionResponse, IContactFolderContactsCollectionPage>(response => {
    var page = response.Value;
    if (response?.AdditionalData != null && response.AdditionalData.ContainsKey("@odata.nextLink"))
    {
        page.InitializeNextPageRequest(Application.GraphConnection.Client, (string)response.AdditionalData["@odata.nextLink"]);
    }
    return page;
});

In this snippet I'm parsing out a ContactFolderContactsCollectionResponse from a batch with steps generated from a get request that would normally return a IContactFolderContactsCollectionPage. The ContactFolderContactsCollectionResponse is fetched by the wrapper internals using

GetResponseByIdAsync<ContactFolderContactsCollectionResponse>(id)

So it's pretty analogous to what you're doing except that there is probably some kind of UserResponse type that you should probably be using instead of User.

In my case the ContactFolderContactsCollectionResponse contains the IContactFolderContactsCollectionPage I actionally want in the Vvalue property hence:

var page = response.Value;

Now, IContactFolderContactsCollectionPage normally has a NextPageRequest property, but when you parse it directly from the ContactFolderContactsCollectionResponse, this is not filled out. Luckily, we can find the raw @odata.nextPage link in the ContactFolderContactsCollectionResponse's AdditionalData dictionary, and we can set it using the IContactFolderContactsCollectionPage.InitializeNextPageRequest methhod. Hence the :

if (response?.AdditionalData != null && response.AdditionalData.ContainsKey("@odata.nextLink"))
{
    page.InitializeNextPageRequest(Application.GraphConnection.Client, (string)response.AdditionalData["@odata.nextLink"]);
}

Hopefully that give you enough thread to pull on. Sorry if the rest of the syntax is confusing, as I said, a lot of it is operating in a wrapper framework I'm building and I don't have time to build and test a clean solution.

It's also possible that the whole thing is different anyway on account of you having a batch with a thousand steps as opposed to a batch whose steps return thousands of objects like as in my case.

Either way, happy hunting.

Luke Kubat
  • 371
  • 1
  • 4
  • Crazy that this bug is still present in the batch response 2 years after this. Thanks for a clean 2 line workaround. In the current SDK, NextLink is an exposed property, you don't have to go to the property bag: var page = memberRes.Value; if (memberRes.NextLink != null) { page.InitializeNextPageRequest(_client, memberRes.NextLink); } – Brett Sep 07 '22 at 04:48
  • Does not surprise me at all. I don't think that Graph batching is super popular. And this is just a parsing error. I doubt they even wrote code for this, I'm guessing they're just counting on json serialization to do the parsing right which means there's probably no unit tests. He'll, the SDK's object model might even be auto-generated from the API documentation. The SSRS SDK does this and it's been badly broken in little ways like this forever. – Luke Kubat Sep 08 '22 at 05:13
  • There is way too much dependency on code templates in these stacks, agreed. I do see very useful performance benefits in batching and so will continue leveraging it but I wish the folks in the PG would spend more time actually using these APIs instead of just dreaming them up and spitting out boilerplate code. – Brett Sep 09 '22 at 18:54