Calling Graph API Via Console Application Using .NET 5

Introduction

 
This is a continuation of the previous article, creating ‘Azure AD Applications’. This console app calls the graph API service to get the users' information in your tenant.
 
Please note that .NET 5 provides capabilities of .NET Core and .NET framework. This is still platform-independent, which means the code will run on Windows machines and as well as Linux, MAC OS machines.
 
Note
You need to have the latest version of Visual Studio Code installed to implement this project by the following steps. This console app is developed using VS Code.
In a nutshell, this is overall what your application does.
Calling Graph API via Console Application using .Net 5 
  1. Console app requests for token
  2. MS Identity platform sends access token on successful authentication.
  3. Console app sends Access Token in the authorization header
  4. Console app gets HTTP response back from the Graph API service

Steps

 
Step1
 
To perform the steps you need to make sure .NET 5 SDKs are installed. To check the version of SDKs installed, open the command prompt and enter the following command
 
dotnet --list-sdks
 
Calling Graph API via Console Application using .Net 5
 
Please check the references section, on how to install .NET 5 SDK.
 
Step 2
 
Create the console app by running the following command.
 
dotnet new console -o consoleapp1.
 
Make sure to create a console app under a specific directory. In this case, I have it installed under C:\Users\Documents\VSCode and created a folder called ‘MSGraph’. This can be created anywhere on your machine.
 
Calling Graph API via Console Application using .Net 5
 
This is just similar to creating a new console app in visual studio IDE.
 
Step 3
 
Install the following dependencies for the console app to consume the graph API successfully. first, change the director to consoleapp1 that just got created.
 
cd consoleapp1
 
Then run the following commands in sequence
 
Calling Graph API via Console Application using .Net 5
 
Microsoft.Identity.Client
 
dotnet add package Microsoft.Identity.Client
 
This command installs the MSAL client into your program, which takes care of generating tokens (Access Token and Refresh Token) for you. ‘dotnet add package’ provides a convenient way to add the NuGet packages to your project.
 
Calling Graph API via Console Application using .Net 5
 
Microsoft.Graph
 
dotnet add package Microsoft.Graph
 
This command installs the models and requests builders to access the v1.0 endpoint with fluent API. 
 
Calling Graph API via Console Application using .Net 5
 
Microsoft.Extensions.Configuration
 
dotnet add package Microsoft.Extensions.Configuration
 
This command installs Configuration class, which is used to read the configuration data from settings such as appsettings.json, Environment variables, Azure Key Vault, Azure App Configuration, command-line arguments, Directory files, In-memory .NET objects, custom providers (installed or created) 
 
Calling Graph API via Console Application using .Net 5
 
Microsoft.Extensions.Configuration.FileExtensions
 
dotnet add package Microsoft.Extensions.Configuration.FileExtensions
 
This command installs the extension methods for Microsoft.Extensions.Configuration class for file-based configuration providers. 
 
Calling Graph API via Console Application using .Net 5
 
Microsoft.Extensions.Configuration.Json
 
dotnet add package Microsoft.Extensions.Configurations.Json
 
this command installs the required methods to access the settings from JSON file.
 
Calling Graph API via Console Application using .Net 5
 
Step 4
 
Open the Visual studio code by typing the command "code .". This directly opens VS code with the correct folder.
 
Calling Graph API via Console Application using .Net 5
 
Calling Graph API via Console Application using .Net 5
 
Note
You might be getting a window message saying ‘Required assets to build and debug”. Just click on yes.
 
Calling Graph API via Console Application using .Net 5
 
Step 5
 
Create a file called ‘appsettings.json’ in the consoleapp1 project.
 
Calling Graph API via Console Application using .Net 5
 
Step 6
 
Update the properties. you should be having following values ready from the previous article ‘Creating Azure AD Application’ 
  • Tenant ID:
  • Application ID:
  • Application Secret:
Update these values in appsettings.json file and save it. note that the values could be different for your specific tenant.
                                                                                 
Step 7
 
Create new folder called ‘Helpers’. Add the helper classes ‘AuthHandler.cs’. This is used to handle the authentication in your application to access the v1.0 endpoint Graph API service.
 
Calling Graph API via Console Application using .Net 5
 
Calling Graph API via Console Application using .Net 5
 
Add the following code in AuthHandler.cs code
  1. using System.Net.Http;  
  2. using System.Threading.Tasks;  
  3. using Microsoft.Graph;  
  4. using System.Threading;  
  5.   
  6. namespace Helpers  
  7. {  
  8.   public class AuthHandler : DelegatingHandler  
  9.   {  
  10.     private IAuthenticationProvider _authenticationProvider;  
  11.   
  12.     public AuthHandler(IAuthenticationProvider authenticationProvider, HttpMessageHandler innerHandler)  
  13.     {  
  14.       InnerHandler = innerHandler;  
  15.       _authenticationProvider = authenticationProvider;  
  16.     }  
  17.   
  18.     protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)  
  19.     {  
  20.       await _authenticationProvider.AuthenticateRequestAsync(request);  
  21.       return await base.SendAsync(request, cancellationToken);  
  22.     }  
  23.   }  
  24. }  
Step 8
 
In a similar way create MsalAutheticationProvider.cs in the Helpers folder. This takes care of token generation and token renewals which is required to access the Graph api.
 
This also adds access token to the authentication header and sends requests to Graph API.
 
Calling Graph API via Console Application using .Net 5
 
add the following code in 'MsalAuthenticationProvider.cs' class
  1. using System.Net.Http;  
  2. using System.Net.Http.Headers;  
  3. using System.Threading.Tasks;  
  4. using Microsoft.Identity.Client;  
  5. using Microsoft.Graph;  
  6.   
  7. namespace Helpers  
  8. {  
  9.   public class MsalAuthenticationProvider : IAuthenticationProvider  
  10.   {  
  11.     private IConfidentialClientApplication _clientApplication;  
  12.     private string[] _scopes;  
  13.   
  14.     public MsalAuthenticationProvider(IConfidentialClientApplication clientApplication, string[] scopes)  
  15.     {  
  16.       _clientApplication = clientApplication;  
  17.       _scopes = scopes;  
  18.     }  
  19.   
  20.     public async Task AuthenticateRequestAsync(HttpRequestMessage request)  
  21.     {  
  22.       var token = await GetTokenAsync();  
  23.       request.Headers.Authorization = new AuthenticationHeaderValue("bearer", token);  
  24.     }  
  25.   
  26.     public async Task<string> GetTokenAsync()  
  27.     {  
  28.       AuthenticationResult authResult = null;  
  29.       authResult = await _clientApplication.AcquireTokenForClient(_scopes).ExecuteAsync();  
  30.       return authResult.AccessToken;  
  31.     }  
  32.   }  
  33. }  
Step 9
 
Consume the Graph API responses in the console app. This is a bit tedious part. So please follow carefully.
 
Calling Graph API via Console Application using .Net 5
 
In the main program.cs add the following references.
  1. using System.Collections.Generic;  
  2. using Microsoft.Graph;  
  3. using Microsoft.Identity.Client;  
  4. using Microsoft.Extensions.Configuration;  
  5. using Helpers;  
Add the static member of type ‘GraphServiceClient’ to the program.cs file which is used to instantiate the client used to call MS Graph.
  1. private static GraphServiceClient _graphClient;  
Calling Graph API via Console Application using .Net 5 
 
for simplicity I have tried to add the lines of code after the main method. Just don’t disturb main method.
 
Step 10
 
It is required to get the configuration settings which is updated in file ‘appsettings.json’. add the following lines of code. 
  1. private static IConfigurationRoot LoadAppSettings()  
  2.         {  
  3.             try  
  4.             {  
  5.                 var config = new ConfigurationBuilder()  
  6.                                 .SetBasePath(System.IO.Directory.GetCurrentDirectory())  
  7.                                 .AddJsonFile("appsettings.json"falsetrue)  
  8.                                 .Build();  
  9.   
  10.                 if (string.IsNullOrEmpty(config["applicationId"]) ||  
  11.                     string.IsNullOrEmpty(config["applicationSecret"]) ||  
  12.                     string.IsNullOrEmpty(config["redirectUri"]) ||  
  13.                     string.IsNullOrEmpty(config["tenantId"]))  
  14.                 {  
  15.                 return null;  
  16.                 }  
  17.   
  18.                 return config;  
  19.             }  
  20.             catch (System.IO.FileNotFoundException)  
  21.             {  
  22.                 return null;  
  23.             }  
  24.         }  
 Calling Graph API via Console Application using .Net 5
 
observe that method is just after the static member we just created.
 
Step 11
 
Create method called ‘AuthorizationProvider’ which will take the setting values from appsettings.json and builds the service to Graph API.
  1. private static IAuthenticationProvider CreateAuthorizationProvider(IConfigurationRoot config)  
  2.         {  
  3.         var clientId = config["applicationId"];  
  4.         var clientSecret = config["applicationSecret"];  
  5.         var redirectUri = config["redirectUri"];  
  6.         var authority = $"https://login.microsoftonline.com/{config["tenantId"]}/v2.0";  
  7.   
  8.         List<string> scopes = new List<string>();  
  9.         scopes.Add("https://graph.microsoft.com/.default");  
  10.   
  11.         var cca = ConfidentialClientApplicationBuilder.Create(clientId)  
  12.                                                 .WithAuthority(authority)  
  13.                                                 .WithRedirectUri(redirectUri)  
  14.                                                 .WithClientSecret(clientSecret)  
  15.                                                 .Build();  
  16.         return new MsalAuthenticationProvider(cca, scopes.ToArray());  
  17.         }  
Calling Graph API via Console Application using .Net 5
 
Notice that this method ‘AuthorizationProvider’ is just after the method LoadAppSettings()
 
Step 12
 
Now consume the response from the Graph API service. For this you need to have the following method ‘GetAuthenticatedGraphClient’ to the program class. this method creates an instance of the graph service client object, which is used to capture the http response.
  1. private static GraphServiceClient GetAuthenticatedGraphClient(IConfigurationRoot config)  
  2.         {  
  3.             var authenticationProvider = CreateAuthorizationProvider(config);  
  4.             _graphClient = new GraphServiceClient(authenticationProvider);  
  5.             return _graphClient;  
  6.         }  
Calling Graph API via Console Application using .Net 5
 
Notice that this method ‘GetAuthenticatedGraphClient’ is just after the ‘CreateAuthorizationProvider’ method.
 
Step 13
 
Now locate the main method and now add the following code to load the values from appsettings.json file. 
  1. var config = LoadAppSettings();  
  2.            if (config == null)  
  3.            {  
  4.            Console.WriteLine("Invalid appsettings.json file.");  
  5.            return;  
  6.            }  
Calling Graph API via Console Application using .Net 5
 
Step 14
 
Now add the following code just after the LoadAppSettings() code that is written before. This code get the authenticated instance of the graph service client, and then writes back the request results got from Graph API service to the console.
  1. var client = GetAuthenticatedGraphClient(config);  
  2.   
  3.             var graphRequest = client.Users.Request();  
  4.   
  5.             var results = graphRequest.GetAsync().Result;  
  6.             foreach(var user in results)  
  7.             {  
  8.             Console.WriteLine(user.Id + ": " + user.DisplayName + " <" + user.Mail + ">");  
  9.             }  
  10.   
  11.             Console.WriteLine("\nGraph Request:");  
  12.             Console.WriteLine(graphRequest.GetHttpRequestMessage().RequestUri);  
  13.         }  
Calling Graph API via Console Application using .Net 5
 
Below is the complete code for program.cs 
  1. using System;  
  2. using System.Collections.Generic;  
  3. using Microsoft.Graph;  
  4. using Microsoft.Identity.Client;  
  5. using Microsoft.Extensions.Configuration;  
  6. using Helpers;  
  7.   
  8. namespace consoleapp1  
  9. {  
  10.     class Program  
  11.     {          
  12.         static void Main(string[] args)  
  13.         {  
  14.             Console.WriteLine("Hello World!");  
  15.             var config = LoadAppSettings();  
  16.             if (config == null)  
  17.             {  
  18.             Console.WriteLine("Invalid appsettings.json file.");  
  19.             return;  
  20.             }  
  21.             var client = GetAuthenticatedGraphClient(config);  
  22.   
  23.             var graphRequest = client.Users.Request();  
  24.   
  25.             var results = graphRequest.GetAsync().Result;  
  26.             foreach(var user in results)  
  27.             {  
  28.             Console.WriteLine(user.Id + ": " + user.DisplayName + " <" + user.Mail + ">");  
  29.             }  
  30.   
  31.             Console.WriteLine("\nGraph Request:");  
  32.             Console.WriteLine(graphRequest.GetHttpRequestMessage().RequestUri);  
  33.         }  
  34.         private static GraphServiceClient _graphClient;  
  35.         private static IConfigurationRoot LoadAppSettings()  
  36.         {  
  37.             try  
  38.             {  
  39.                 var config = new ConfigurationBuilder()  
  40.                                 .SetBasePath(System.IO.Directory.GetCurrentDirectory())  
  41.                                 .AddJsonFile("appsettings.json"falsetrue)  
  42.                                 .Build();  
  43.   
  44.                 if (string.IsNullOrEmpty(config["applicationId"]) ||  
  45.                     string.IsNullOrEmpty(config["applicationSecret"]) ||  
  46.                     string.IsNullOrEmpty(config["redirectUri"]) ||  
  47.                     string.IsNullOrEmpty(config["tenantId"]))  
  48.                 {  
  49.                 return null;  
  50.                 }  
  51.   
  52.                 return config;  
  53.             }  
  54.             catch (System.IO.FileNotFoundException)  
  55.             {  
  56.                 return null;  
  57.             }  
  58.         }  
  59.         private static IAuthenticationProvider CreateAuthorizationProvider(IConfigurationRoot config)  
  60.         {  
  61.         var clientId = config["applicationId"];  
  62.         var clientSecret = config["applicationSecret"];  
  63.         var redirectUri = config["redirectUri"];  
  64.         var authority = $"https://login.microsoftonline.com/{config["tenantId"]}/v2.0";  
  65.   
  66.         List<string> scopes = new List<string>();  
  67.         scopes.Add("https://graph.microsoft.com/.default");  
  68.   
  69.         var cca = ConfidentialClientApplicationBuilder.Create(clientId)  
  70.                                                 .WithAuthority(authority)  
  71.                                                 .WithRedirectUri(redirectUri)  
  72.                                                 .WithClientSecret(clientSecret)  
  73.                                                 .Build();  
  74.         return new MsalAuthenticationProvider(cca, scopes.ToArray());  
  75.         }  
  76.         private static GraphServiceClient GetAuthenticatedGraphClient(IConfigurationRoot config)  
  77.         {  
  78.             var authenticationProvider = CreateAuthorizationProvider(config);  
  79.             _graphClient = new GraphServiceClient(authenticationProvider);  
  80.             return _graphClient;  
  81.         }  
  82.     }  
  83. }  

Build and Test the application

 
Step 1
 
Run the following command in command prompt to ensure the developer certificate has been trusted.
 
dotnet dev-certs https –trust
 
Calling Graph API via Console Application using .Net 5
 
In this case, I might have already trusted the developer certificates in my previous projects. Usually you will be prompted with a message box, to trust the developer certificates, and select yes.
 
Step 2
 
build the application by simply running the following command. This is similar to building application making sure it is compiled successfully in visual studio IDE.
 
dotnet build
 
Calling Graph API via Console Application using .Net 5
 
Step 3
 
Run the application by running the following command
 
dotnet run
 
Step 4
 
Observe that now on successful compilation and run, you should have all the users displayed in your tenant. Since this is developer tenant, I have only few users in this case.
 
Also notice that the URL that is generated by SDK, which is used to send to Graph API service.
 
Calling Graph API via Console Application using .Net 5
 

Conclusion

 
The complete source code is mentioned in the references section. Thus in this article, we have created a console app using .Net 5 which requests token from the Microsoft IDentity platform, with that access token it calls the Graph API service to get the information about the users in the Office 365 Tenant. 
 
References
  • Source Code: available here
  • https://dotnet.microsoft.com/download/dotnet/5.0
  • https://docs.microsoft.com/en-us/azure/active-directory/develop/tutorial-v2-windows-desktop
  • https://docs.microsoft.com/en-us/graph/sdks/sdk-installation
  • https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-5.0
  • https://docs.microsoft.com/en-us/archive/msdn-magazine/2016/february/essential-net-configuration-in-net-core
  • https://stackoverflow.com/questions/52156484/how-exactly-does-microsoft-extensions-configuration-dependent-on-asp-net-core
  • https://www.nuget.org/packages/Microsoft.Extensions.Configuration.FileExtensions/
  • https://docs.microsoft.com/en-us/learn/modules/optimize-data-usage/3-exercise-retrieve-control-information-returned-from-microsoft-graph