Search code examples
c#azure-devopsazure-ad-b2cvisual-studio-2022

.Request() not working in C# with an Azure AD B2C


I have an Admin application written in C# with the Microsoft.Graph.Beta extension and this uses .Request() to allow users from a B2C to be viewed and searched, I have a separate application that uses the new 5.52.0 Microsoft Graph and Azure.Identity that can be used to add and update users in the B2C using the Users.PostAsync method. With this being the more secure application I need the features of the first one to be migrated over but the new Graph appears to have made .Request() redundant which is the only method I know to get data from the B2C.

Here is the viewing code from the first application -

 public static async Task ListUsers(GraphServiceClient graphClient)
 {
     Console.WriteLine("Getting list of users...");

     // Get all users (one page)
     var result = await graphClient.Users
         .Request()
         .Select(e => new
         {
             e.DisplayName,
             e.Id,
             e.Identities,
             e.BusinessPhones
         })
         .GetAsync();

     // Calculate maximum lengths
     int maxDisplayNameLength = result.CurrentPage.Max(u => u.DisplayName.Length);
     int maxIdLength = result.CurrentPage.Max(u => u.Id.Length);
     int maxEmailLength = result.CurrentPage
         .Where(u => u.Identities.Any(i => i.SignInType == "emailAddress")) // Filter users with email addresses
         .Select(u => u.Identities.FirstOrDefault(i => i.SignInType == "emailAddress")?.IssuerAssignedId)
         .Where(email => email != null)
         .Max(email => email.Length);

     bool isFirst = true;

     foreach (var user in result.CurrentPage)
     {
         // Get email if available
         string email = user.Identities.FirstOrDefault(i => i.SignInType == "emailAddress")?.IssuerAssignedId;

         // If user has no email, skip to the next iteration
         if (email == null)
             continue;

         // Get phone numbers
         string phoneNumbers = string.Join(", ", user.BusinessPhones);

         if (isFirst)
         {
             Console.WriteLine("------------------------");
             isFirst = false;
         }

         // Format output with alignment based on maximum lengths
         Console.WriteLine($"DisplayName: {user.DisplayName.PadRight(maxDisplayNameLength)}");
         Console.WriteLine($"Id: {user.Id.PadRight(maxIdLength)}");
         Console.WriteLine($"Email: {email?.PadRight(maxEmailLength) ?? string.Empty}");
         Console.WriteLine($"Phone Numbers: {phoneNumbers}"); // Display phone numbers
         Console.WriteLine("------------------------"); // Add a line separator
     }
 }

Which works flawlessly in the older Graph version but I need it migrated into the new application for security reasons. Below is an attempt at the same logic in the new application and if ran you would notice it throws errors relating to the .Request() -

`static async Task ListUsers()
        {
            var scopes = new[] { "https://graph.microsoft.com/.default" };
            var tenantId = "...";
            var clientId = "...";
            var clientSecret = "...";

            var clientSecretCredential = new ClientSecretCredential(tenantId, clientId, clientSecret);
            var graphClient = new GraphServiceClient(clientSecretCredential, scopes);

            try
            {
                // Retrieve users from Microsoft Graph
                var users = await graphClient.Users.Request().GetAsync();

                // Display user details
                foreach (var user in users)
                {
                    Console.WriteLine($"Display Name: {user.DisplayName}");
                    Console.WriteLine($"Given Name: {user.GivenName}");
                    Console.WriteLine($"Surname: {user.Surname}");
                    Console.WriteLine($"Email Address: {user.Mail}");
                    Console.WriteLine($"Business Phone Number: {user.BusinessPhones?[0]}");
                    Console.WriteLine();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error listing users: {ex.Message}");
            }
        }`

Is there a new method in modern Graph to replace this?


Solution

  • Note that: Request() is removed from the latest version of Microsoft Graph and hence you need to remove the Request() from the code to resolve the error. Refer this GitHub Blog.

    To resolve the error, modify the code like below:

    using Microsoft.Graph;
    using Azure.Identity;
    
    class Program
    {
        static async Task Main()
        {
            string tenantId = "TenantID";
            string clientId = "ClientID";
            string clientSecret = "ClientSecret";
            var clientSecretCredential = new ClientSecretCredential(tenantId, clientId, clientSecret);
    
            var graphClient = new GraphServiceClient(clientSecretCredential);
    
            try
            {
    
                var users = await graphClient.Users.GetAsync((requestConfiguration) =>
                {
                    requestConfiguration.QueryParameters.Select = new string[] { "displayName", "GivenName", "Surname", "Mail" };
                });
    
                foreach (var user in users.Value)
                {
                    Console.WriteLine($"Display Name: {user.DisplayName}");
                    Console.WriteLine($"Given Name: {user.GivenName}");
                    Console.WriteLine($"Surname: {user.Surname}");
                    Console.WriteLine($"Street Address: {user.Mail}");
                    Console.WriteLine(" ");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error listing users: {ex.Message}");
            }
        }
    }
    

    enter image description here