0

I currently use the following code to pull information from Azure AD for a company directory:

List<QueryOption> options = new List<QueryOption>();
options.Add(new QueryOption("$filter", "accountEnabled%20eq%20true"));
options.Add(new QueryOption("$select", "displayName,companyName,profilePhoto,userPrincipalName"));

IGraphServiceUsersCollectionPage users = await gsc.Users.Request(options).GetAsync();
userResult.AddRange(users);
while (users.NextPageRequest != null)
{
    users = await users.NextPageRequest.GetAsync();
    userResult.AddRange(users);
}

It works relatively well, retrieving ~400 users' worth of data in roughly 5 seconds (I believe I can drop that time, but I'm not 100% clear on the best practices for dealing with async calls yet). The issue comes when I implement the following code to pull the user profile photos:

foreach(User u in userResult)
{
    Stream photo = await gsc.Users[u.UserPrincipalName].Photo.Content.Request().GetAsync();
    byte[] buffer = new byte[16 * 1024];

    using (MemoryStream ms = new MemoryStream())
    {
        int read;
        while ((read = photo.Read(buffer, 0, buffer.Length)) > 0)
            ms.Write(buffer, 0, read);
        imgMe.ImageUrl = "data:image/jpg;base64," + Convert.ToBase64String(ms.ToArray());
    }
}

This bit raises the page load time to over 30 seconds, and I'm having issues reducing that. So my questions in this specific situation are as follows:

  1. Why does the original query (where I do specify profilePhoto in the select options) not actually pull the profile photo information?
  2. What am I doing wrong here that creates such a drastic load time?
James Carr
  • 31
  • 6
  • consider moving the code inside foreach into a method that returns Task and do a Task.WhenAll on all the tasks created for the users – Matt.G Nov 25 '19 at 21:32

1 Answers1

0
1. Why does the original query (where I do specify profilePhoto in the select options) not actually pull the profile photo information?

In Microsoft Graph API, it is designed as this. You can use Get a user API to get basic user profile, at the same time, you need to use Get photo API to get photo.

So, in SDK, you will have the same experience.

2. What am I doing wrong here that creates such a drastic load time?

Actually, there is nothing wrong. But there is way to reduce the time cost. As @Matt.G said in comment, you can create a separated method which returns a Task for downloading photo data. And then you can download photos in parallel.

For more about this, you may refer to the official tutorial: How to extend the async walkthrough by using Task.WhenAll (C#)

Community
  • 1
  • 1
Jack Jia
  • 5,268
  • 1
  • 12
  • 14