Friday, October 14, 2016

Retrieve paginated data from Azure AD via Microsoft Graph Client library

In this post I will show how to retrieve paginated data from Azure AD using MS Graph .Net client library. As we already saw from previous examples (see e.g. Create Azure AD group and set group owner using Microsoft Graph Client library) client library is adopted for asynchronous usage (we can call its methods asynchronously using async/await C# keywords). In addition to that it also restricts number of objects returned from single request, e.g. when you get list of users via GraphServiceClient.Users.Request().GetAsync() call it will return only 100 users. In order to get other users we will need to load all pages by 100 users each. The following example shows how to do it:

   1: static async void enumUsers()
   2: {
   3:     var graph = new GraphServiceClient(new AzureAuthenticationProvider());
   4:     try
   5:     {
   6:         var users = await graph.Users.Request().GetAsync();
   7:         int requestNumber = 1;
   8:         while (users.Count > 0)
   9:         {
  10:             Console.WriteLine("Request number: {0}", requestNumber++);
  11:             foreach (var u in users)
  12:             {
  13:                 Console.WriteLine("User: {0} ({1})", u.DisplayName,
  14:                     u.UserPrincipalName);
  15:             }
  16:  
  17:             if (users.NextPageRequest != null)
  18:             {
  19:                 users = await users.NextPageRequest.GetAsync();
  20:             }
  21:             else
  22:             {
  23:                 break;
  24:             }
  25:         }
  26:     }
  27:     catch (ServiceException x)
  28:     {
  29:         Console.WriteLine("Exception occured: {0}", x.Error);
  30:     }
  31: }
  32:  
  33:  
  34:  
  35: public class AzureAuthenticationProvider : IAuthenticationProvider
  36: {
  37:     public async Task AuthenticateRequestAsync(HttpRequestMessage request)
  38:     {
  39:         string clientId = ConfigurationManager.AppSettings["ClientId"];
  40:         string clientSecret = ConfigurationManager.AppSettings["ClientSecret"];
  41:         string authority = ConfigurationManager.AppSettings["AuthorityUrl"];
  42:     
  43:         AuthenticationContext authContext = new AuthenticationContext(authority);
  44:     
  45:         ClientCredential creds = new ClientCredential(clientId, clientSecret);
  46:     
  47:         Console.WriteLine("before: get token");
  48:         AuthenticationResult authResult = await
  49: authContext.AcquireTokenAsync("https://graph.microsoft.com/", creds);
  50:         Console.WriteLine("after: get token {0}", authResult.AccessToken);
  51:     
  52:         request.Headers.Add("Authorization", "Bearer " + authResult.AccessToken);
  53:     }
  54: }

I.e. we call graph.Users.Request().GetAsync() first (line 6) and then call graph.Users.NextPageRequest.GetAsync() (line 19) until next page won’t be empty. For convenience I also added number of request made to Graph API to the console (line 10) so it will be visible how many requests are needed for iterating through all users. For authentication we use application id and secret in custom AzureAuthenticationProvider as described in the following article: Work with Azure AD via Microsoft Graph API.

6 comments:

  1. erratum: async/wait -> async/Await

    ReplyDelete
  2. of course, thank you, I updated the post

    ReplyDelete
  3. I am not able to get users more than 999 by this code

    ReplyDelete
  4. I have 1000 users on my azure account

    As per microsoft document we can pull max 999 users so this code by default pull 999 users from azure ad what about next 1 user i am not able to get it by this code

    you just pull 999 users and create list using users.NextPageRequest parameter
    can you help me on this.

    ReplyDelete


  5. public static async Task> GetUsersAsync()
    {
    var graphClient = GetAuthenticatedClient();
    List allUsers = new List();
    var users = await graphClient.Users.Request().Top(998)
    .Select("displayName,mail,givenName,surname,id")
    .GetAsync();

    while (users.Count > 0)
    {
    allUsers.AddRange(users);
    if (users.NextPageRequest != null)
    {
    users = await users.NextPageRequest
    .GetAsync();
    }
    else
    {
    break;
    }
    }
    return allUsers;
    }
    This code is workable.

    ReplyDelete