Build .NET apps with Microsoft Graph
This tutorial teaches you how to build a .NET console app that uses the Microsoft Graph API.
Tip
If you prefer to just download the completed tutorial, you can download or clone the GitHub repository.
Prerequisites
Before you start this tutorial, you should have the .NET SDK installed on your development machine.
You should also have either a personal Microsoft account with a mailbox on Outlook.com, or a Microsoft work or school account. If you don't have a Microsoft account, there are a couple of options to get a free account:
- You can sign up for a new personal Microsoft account.
- You can sign up for the Microsoft 365 Developer Program to get a free Microsoft 365 subscription.
Note
This tutorial was written with .NET SDK version 6.0.102. The steps in this guide may work with other versions, but that has not been tested.
Register the app in the portal
In this exercise you will register a new application in Azure Active Directory to enable user authentication. You can register an application using the Azure Active Directory admin center, or by using the Microsoft Graph PowerShell SDK.
Register application for user authentication
In this section you will register an application that will support user authentication using device code flow.
Open a browser and navigate to the Azure Active Directory admin center and login using a personal account (aka: Microsoft Account) or Work or School Account.
Select Azure Active Directory in the left-hand navigation, then select App registrations under Manage.
Select New registration. Enter a name for your application, for example,
.NET Graph Tutorial
.Set Supported account types as desired. The options are:
Option Who can sign in? Accounts in this organizational directory only Only users in your Microsoft 365 organization Accounts in any organizational directory Users in any Microsoft 365 organization (work or school accounts) Accounts in any organizational directory ... and personal Microsoft accounts Users in any Microsoft 365 organization (work or school accounts) and personal Microsoft accounts Leave Redirect URI empty.
Select Register. On the application's Overview page, copy the value of the Application (client) ID and save it, you will need it in the next step. If you chose Accounts in this organizational directory only for Supported account types, also copy the Directory (tenant) ID and save it.
Select Authentication under Manage. Locate the Advanced settings section and change the Allow public client flows toggle to Yes, then choose Save.
Note
Notice that you did not configure any Microsoft Graph permissions on the app registration. This is because the sample will use dynamic consent to request specific permissions for user authentication.
Create a .NET console app
Begin by creating a new .NET console project using the .NET CLI.
Open your command-line interface (CLI) in a directory where you want to create the project. Run the following command.
dotnet new console -o GraphTutorial
Once the project is created, verify that it works by changing the current directory to the GraphTutorial directory and running the following command in your CLI.
dotnet run
If it works, the app should output
Hello, World!
.
Install dependencies
Before moving on, add some additional dependencies that you will use later.
- .NET configuration packages to read application configuration from appsettings.json.
- Azure Identity client library for .NET to authenticate the user and acquire access tokens.
- Microsoft Graph .NET client library to make calls to the Microsoft Graph.
Run the following commands in your CLI to install the dependencies.
dotnet add package Microsoft.Extensions.Configuration.Binder
dotnet add package Microsoft.Extensions.Configuration.Json
dotnet add package Azure.Identity
dotnet add package Microsoft.Graph
Load application settings
In this section you'll add the details of your app registration to the project.
Create a file in the GraphTutorial directory named appsettings.json and add the following code.
{ "settings": { "clientId": "YOUR_CLIENT_ID_HERE", "clientSecret": "YOUR_CLIENT_SECRET_HERE_IF_USING_APP_ONLY", "tenantId": "YOUR_TENANT_ID_HERE_IF_USING_APP_ONLY", "authTenant": "common", "graphUserScopes": [ "user.read", "mail.read", "mail.send" ] } }
Update the values according to the following table.
Setting Value clientId
The client ID of your app registration authTenant
If you chose the option to only allow users in your organization to sign in, change this value to your tenant ID. Otherwise leave as common
.Tip
Optionally, you can set these values in a separate file named appsettings.Development.json, or in the .NET Secret Manager.
Update GraphTutorial.csproj to copy appsettings.json to the output directory. Add the following code between the
<Project>
and</Project>
lines.<ItemGroup> <None Include="appsettings*.json"> <CopyToOutputDirectory>Always</CopyToOutputDirectory> </None> </ItemGroup>
Create a file in the GraphTutorial directory named Settings.cs and add the following code.
using Microsoft.Extensions.Configuration; public class Settings { public string? ClientId { get; set; } public string? ClientSecret { get; set; } public string? TenantId { get; set; } public string? AuthTenant { get; set; } public string[]? GraphUserScopes { get; set; } public static Settings LoadSettings() { // Load settings IConfiguration config = new ConfigurationBuilder() // appsettings.json is required .AddJsonFile("appsettings.json", optional: false) // appsettings.Development.json" is optional, values override appsettings.json .AddJsonFile($"appsettings.Development.json", optional: true) // User secrets are optional, values override both JSON files .AddUserSecrets<Program>() .Build(); return config.GetRequiredSection("Settings").Get<Settings>(); } }
Design the app
In this section you will create a simple console-based menu.
Open ./Program.cs and replace its entire contents with the following code.
Console.WriteLine(".NET Graph Tutorial\n"); var settings = Settings.LoadSettings(); // Initialize Graph InitializeGraph(settings); // Greet the user by name await GreetUserAsync(); int choice = -1; while (choice != 0) { Console.WriteLine("Please choose one of the following options:"); Console.WriteLine("0. Exit"); Console.WriteLine("1. Display access token"); Console.WriteLine("2. List my inbox"); Console.WriteLine("3. Send mail"); Console.WriteLine("4. List users (requires app-only)"); Console.WriteLine("5. Make a Graph call"); try { choice = int.Parse(Console.ReadLine() ?? string.Empty); } catch (System.FormatException) { // Set to invalid value choice = -1; } switch(choice) { case 0: // Exit the program Console.WriteLine("Goodbye..."); break; case 1: // Display access token await DisplayAccessTokenAsync(); break; case 2: // List emails from user's inbox await ListInboxAsync(); break; case 3: // Send an email message await SendMailAsync(); break; case 4: // List users await ListUsersAsync(); break; case 5: // Run any Graph code await MakeGraphCallAsync(); break; default: Console.WriteLine("Invalid choice! Please try again."); break; } }
Add the following placeholder methods at the end of the file. You'll implement them in later steps.
void InitializeGraph() { // TODO } async Task GreetUserAsync() { // TODO } async Task DisplayAccessTokenAsync() { // TODO } async Task ListInboxAsync() { // TODO } async Task SendMailAsync() { // TODO } async Task ListUsersAsync() { // TODO } async Task MakeGraphCallAsync() { // TODO }
This implements a basic menu and reads the user's choice from the command line.
Add user authentication
In this section you will extend the application from the previous exercise to support authentication with Azure AD. This is required to obtain the necessary OAuth access token to call the Microsoft Graph. In this step you will integrate the Azure Identity client library for .NET into the application and configure authentication for the Microsoft Graph .NET client library.
The Azure Identity library provides a number of TokenCredential
classes that implement OAuth2 token flows. The Microsoft Graph client library uses those classes to authenticate calls to Microsoft Graph. In this example, we'll use the following TokenCredential
classes.
DeviceCodeCredential
implements the device code flow for user authentication.ClientSecretCredential
implements the client credentials flow for app-only authentication. You will use this class in the optional app-only sections.
Configure Graph client for user authentication
In this section you will use the DeviceCodeCredential
class to request an access token by using the device code flow.
Create a new file in the GraphTutorial directory named GraphHelper.cs and add the following code to that file.
using Azure.Core; using Azure.Identity; using Microsoft.Graph; class GraphHelper { }
Add the following code to the
GraphHelper
class.// Settings object private static Settings? _settings; // User auth token credential private static DeviceCodeCredential? _deviceCodeCredential; // Client configured with user authentication private static GraphServiceClient? _userClient; public static void InitializeGraphForUserAuth(Settings settings, Func<DeviceCodeInfo, CancellationToken, Task> deviceCodePrompt) { _settings = settings; _deviceCodeCredential = new DeviceCodeCredential(deviceCodePrompt, settings.AuthTenant, settings.ClientId); _userClient = new GraphServiceClient(_deviceCodeCredential, settings.GraphUserScopes); }
Replace the empty
InitializeGraph
function in Program.cs with the following.void InitializeGraph(Settings settings) { GraphHelper.InitializeGraphForUserAuth(settings, (info, cancel) => { // Display the device code message to // the user. This tells them // where to go to sign in and provides the // code to use. Console.WriteLine(info.Message); return Task.FromResult(0); }); }
This code declares two private properties, a DeviceCodeCredential
object and a GraphServiceClient
object. The InitializeGraphForUserAuth
function creates a new instance of DeviceCodeCredential
, then uses that instance to create a new instance of GraphServiceClient
. Every time an API call is made to Microsoft Graph through the _userClient
, it will use the provided credential to get an access token.
Test the DeviceCodeCredential
Next, add code to get an access token from the DeviceCodeCredential
.
Add the following function to the
GraphHelper
class.public static async Task<string> GetUserTokenAsync() { // Ensure credential isn't null _ = _deviceCodeCredential ?? throw new System.NullReferenceException("Graph has not been initialized for user auth"); // Ensure scopes isn't null _ = _settings?.GraphUserScopes ?? throw new System.ArgumentNullException("Argument 'scopes' cannot be null"); // Request token with given scopes var context = new TokenRequestContext(_settings.GraphUserScopes); var response = await _deviceCodeCredential.GetTokenAsync(context); return response.Token; }
Replace the empty
DisplayAccessTokenAsync
function in Program.cs with the following.async Task DisplayAccessTokenAsync() { try { var userToken = await GraphHelper.GetUserTokenAsync(); Console.WriteLine($"User token: {userToken}"); } catch (Exception ex) { Console.WriteLine($"Error getting user access token: {ex.Message}"); } }
Build and run the app. Enter
1
when prompted for an option. The application displays a URL and device code..NET Graph Tutorial Please choose one of the following options: 0. Exit 1. Display access token 2. List my inbox 3. Send mail 4. List users (requires app-only) 1 To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code RB2RUD56D to authenticate.
Open a browser and browse to the URL displayed. Enter the provided code and sign in.
Important
Be mindful of any existing Microsoft 365 accounts that are logged into your browser when browsing to
https://microsoft.com/devicelogin
. Use browser features such as profiles, guest mode, or private mode to ensure that you authenticate as the account you intend to use for testing.Once completed, return to the application to see the access token.
Tip
For validation and debugging purposes only, you can decode user access tokens (for work or school accounts only) using Microsoft's online token parser at https://jwt.ms. This can be useful if you encounter token errors when calling Microsoft Graph. For example, verifying that the
scp
claim in the token contains the expected Microsoft Graph permission scopes.
Get user
In this section you will incorporate the Microsoft Graph into the application. For this application, you will use the Microsoft Graph .NET Client Library to make calls to Microsoft Graph.
Open ./GraphHelper.cs and add the following function to the GraphHelper class.
public static Task<User> GetUserAsync() { // Ensure client isn't null _ = _userClient ?? throw new System.NullReferenceException("Graph has not been initialized for user auth"); return _userClient.Me .Request() .Select(u => new { // Only request specific properties u.DisplayName, u.Mail, u.UserPrincipalName }) .GetAsync(); }
Replace the empty
GreetUserAsync
function in Program.cs with the following.async Task GreetUserAsync() { try { var user = await GraphHelper.GetUserAsync(); Console.WriteLine($"Hello, {user?.DisplayName}!"); // For Work/school accounts, email is in Mail property // Personal accounts, email is in UserPrincipalName Console.WriteLine($"Email: {user?.Mail ?? user?.UserPrincipalName ?? ""}"); } catch (Exception ex) { Console.WriteLine($"Error getting user: {ex.Message}"); } }
If you run the app now, after you log in the app welcomes you by name.
Hello, Megan Bowen!
Email: MeganB@contoso.com
Code explained
Consider the code in the GetUserAsync
function. It's only a few lines, but there are some key details to notice.
Accessing 'me'
The function uses the _userClient.Me
request builder, which builds a request to the Get user API. This API is accessible two ways:
GET /me
GET /users/{user-id}
In this case, the code will call the GET /me
API endpoint. This is a shortcut method to get the authenticated user without knowing their user ID.
Note
Because the GET /me
API endpoint gets the authenticated user, it is only available to apps that use user authentication. App-only authentication apps cannot access this endpoint.
Requesting specific properties
The function uses the Select
method on the request to specify the set of properties it needs. This adds the $select query parameter to the API call.
Strongly-typed return type
The function returns a Microsoft.Graph.User
object deserialized from the JSON response from the API. Because the code uses Select
, only the requested properties will have values in the returned User
object. All other properties will have default values.
List inbox
In this section you will add the ability to list messages in the user's email inbox.
Open ./GraphHelper.cs and add the following function to the GraphHelper class.
public static Task<IMailFolderMessagesCollectionPage> GetInboxAsync() { // Ensure client isn't null _ = _userClient ?? throw new System.NullReferenceException("Graph has not been initialized for user auth"); return _userClient.Me // Only messages from Inbox folder .MailFolders["Inbox"] .Messages .Request() .Select(m => new { // Only request specific properties m.From, m.IsRead, m.ReceivedDateTime, m.Subject }) // Get at most 25 results .Top(25) // Sort by received time, newest first .OrderBy("ReceivedDateTime DESC") .GetAsync(); }
Replace the empty
ListInboxAsync
function in Program.cs with the following.async Task ListInboxAsync() { try { var messagePage = await GraphHelper.GetInboxAsync(); // Output each message's details foreach (var message in messagePage.CurrentPage) { Console.WriteLine($"Message: {message.Subject ?? "NO SUBJECT"}"); Console.WriteLine($" From: {message.From?.EmailAddress?.Name}"); Console.WriteLine($" Status: {(message.IsRead!.Value ? "Read" : "Unread")}"); Console.WriteLine($" Received: {message.ReceivedDateTime?.ToLocalTime().ToString()}"); } // If NextPageRequest is not null, there are more messages // available on the server // Access the next page like: // messagePage.NextPageRequest.GetAsync(); var moreAvailable = messagePage.NextPageRequest != null; Console.WriteLine($"\nMore messages available? {moreAvailable}"); } catch (Exception ex) { Console.WriteLine($"Error getting user's inbox: {ex.Message}"); } }
Run the app, sign in, and choose option 2 to list your inbox.
Please choose one of the following options: 0. Exit 1. Display access token 2. List my inbox 3. Send mail 4. List users (requires app-only) 5. Make a Graph call 2 Message: Updates from Ask HR and other communities From: Contoso Demo on Yammer Status: Read Received: 12/30/2021 4:54:54 AM -05:00 Message: Employee Initiative Thoughts From: Patti Fernandez Status: Read Received: 12/28/2021 5:01:10 PM -05:00 Message: Voice Mail (11 seconds) From: Alex Wilber Status: Unread Received: 12/28/2021 5:00:46 PM -05:00 Message: Our Spring Blog Update From: Alex Wilber Status: Unread Received: 12/28/2021 4:49:46 PM -05:00 Message: Atlanta Flight Reservation From: Alex Wilber Status: Unread Received: 12/28/2021 4:35:42 PM -05:00 Message: Atlanta Trip Itinerary - down time From: Alex Wilber Status: Unread Received: 12/28/2021 4:22:04 PM -05:00 ... More messages available? True
Code explained
Consider the code in the GetInboxAsync
function.
Accessing well-known mail folders
The function uses the _userClient.Me.MailFolders["Inbox"].Messages
request builder, which builds a request to the List messages API. Because it includes the MailFolders["Inbox"]
request builder, the API will only return messages in the requested mail folder. In this case, because the inbox is a default, well-known folder inside a user's mailbox, it's accessible via its well-known name. Non-default folders are accessed the same way, by replacing the well-known name with the mail folder's ID property. For details on the available well-known folder names, see mailFolder resource type.
Accessing a collection
Unlike the GetUserAsync
function from the previous section, which returns a single object, this method returns a collection of messages. Most APIs in Microsoft Graph that return a collection do not return all available results in a single response. Instead, they use paging to return a portion of the results while providing a method for clients to request the next "page".
Default page sizes
APIs that use paging implement a default page size. For messages, the default value is 10. Clients can request more (or less) by using the $top query parameter. In GetInboxAsync
, this is accomplished with the .Top(25)
method.
Note
The value passed to .Top()
is an upper-bound, not an explicit number. The API returns a number of messages up to the specified value.
Getting subsequent pages
If there are more results available on the server, collection responses include an @odata.nextLink
property with an API URL to access the next page. The .NET client library exposes this as the NextPageRequest
property on collection page objects. If this property is non-null, there are more results available.
The NextPageRequest
property exposes a GetAsync
method which returns the next page.
Sorting collections
The function uses the OrderBy
method on the request to request results sorted by the time the message is received (ReceivedDateTime
property). It includes the DESC
keyword so that messages received more recently are listed first. This adds the $orderby query parameter to the API call.
Send mail
In this section you will add the ability to send an email message as the authenticated user.
Open ./GraphHelper.cs and add the following function to the GraphHelper class.
public static async Task SendMailAsync(string subject, string body, string recipient) { // Ensure client isn't null _ = _userClient ?? throw new System.NullReferenceException("Graph has not been initialized for user auth"); // Create a new message var message = new Message { Subject = subject, Body = new ItemBody { Content = body, ContentType = BodyType.Text }, ToRecipients = new Recipient[] { new Recipient { EmailAddress = new EmailAddress { Address = recipient } } } }; // Send the message await _userClient.Me .SendMail(message) .Request() .PostAsync(); }
Replace the empty
SendMailAsync
function in Program.cs with the following.async Task SendMailAsync() { try { // Send mail to the signed-in user // Get the user for their email address var user = await GraphHelper.GetUserAsync(); var userEmail = user?.Mail ?? user?.UserPrincipalName; if (string.IsNullOrEmpty(userEmail)) { Console.WriteLine("Couldn't get your email address, canceling..."); return; } await GraphHelper.SendMailAsync("Testing Microsoft Graph", "Hello world!", userEmail); Console.WriteLine("Mail sent."); } catch (Exception ex) { Console.WriteLine($"Error sending mail: {ex.Message}"); } }
Run the app, sign in, and choose option 3 to send an email to yourself.
Please choose one of the following options: 0. Exit 1. Display access token 2. List my inbox 3. Send mail 4. List users (requires app-only) 5. Make a Graph call 3 Mail sent.
Note
If you are testing with a developer tenant from the Microsoft 365 Developer Program, the email you send may not be delivered, and you may receive a non-delivery report. If this happens to you, please contact support via the Microsoft 365 admin center.
Code explained
Consider the code in the SendMailAsync
function.
Sending mail
The function uses the _userClient.Me.SendMail
request builder, which builds a request to the Send mail API. The request builder takes a Message
object representing the message to send.
Creating objects
Unlike the previous calls to Microsoft Graph that only read data, this call creates data. To do this with the client library you create an instance of the class representing the data (in this case, Microsoft.Graph.Message
) using the new
keyword, set the desired properties, then send it in the API call. Because the call is sending data, the PostAsync
method is used instead of GetAsync
.
Optional: configure app-only authentication
In this section you will update the app registration from the previous section to support app-only authentication. App-only authentication is a good choice for background services, and there are also some APIs that only support app-only authentication. You only need to complete this section if you intend to use the app-only portions of this tutorial. If not, you can safely skip to the next step.
Important
The steps in this section require a work/school account with the Global administrator role.
Open the app registration from the previous section in the Azure AD admin center.
Select API permissions under Manage.
Remove the default User.Read permission under Configured permissions by selecting the ellipses (...) in its row and selecting Remove permission.
Select Add a permission, then Microsoft Graph.
Select Application permissions.
Select User.Read.All, then select Add permissions.
Select Grant admin consent for..., then select Yes to provide admin consent for the selected permission.
Select Certificates and secrets under Manage, then select New client secret.
Enter a description, choose a duration, and select Add.
Copy the secret from the Value column, you will need it in the next steps.
Important
This client secret is never shown again, so make sure you copy it now.
Note
Notice that, unlike the steps when registering for user authentication, in this section you did configure Microsoft Graph permissions on the app registration. This is because app-only auth uses the client credentials flow, which requires that permissions be configured on the app registration. See The .default scope for details.
Optional: add app-only authentication
In this section you will add app-only authentication to the application. This section is optional, and requires completion of Optional: configure app-only authentication. These steps can only be completed with a work or school account.
Configure Graph client for app-only authentication
In this section you will use the ClientSecretCredential
class to request an access token by using the client credentials flow.
Update the value of
tenantId
in appsettings.json (or appsettings.Development.json) with your organization's tenant ID.Add your client secret to the .NET Secret Manager. In your command-line interface, change the directory to the location of GraphTutorial.csproj and run the following commands, replacing <client-secret> with your client secret.
dotnet user-secrets init dotnet user-secrets set settings:clientSecret <client-secret>
Note
The .NET Secret Manager is only available during development. Production apps should store client secrets in a secure store, such as Azure Key Vault.
Open ./GraphHelper.cs and add the following code to the GraphHelper class.
// App-ony auth token credential private static ClientSecretCredential? _clientSecretCredential; // Client configured with app-only authentication private static GraphServiceClient? _appClient; private static void EnsureGraphForAppOnlyAuth() { // Ensure settings isn't null _ = _settings ?? throw new System.NullReferenceException("Settings cannot be null"); if (_clientSecretCredential == null) { _clientSecretCredential = new ClientSecretCredential( _settings.TenantId, _settings.ClientId, _settings.ClientSecret); } if (_appClient == null) { _appClient = new GraphServiceClient(_clientSecretCredential, // Use the default scope, which will request the scopes // configured on the app registration new[] {"https://graph.microsoft.com/.default"}); } }
Optional: list users
In this section you will add the ability to list all users in your Azure Active Directory using app-only authentication. This section is optional, and requires completion of Optional: configure app-only authentication and Optional: add app-only authentication. These steps can only be completed with a work or school account.
Open ./GraphHelper.cs and add the following function to the GraphHelper class.
public static Task<IGraphServiceUsersCollectionPage> GetUsersAsync() { EnsureGraphForAppOnlyAuth(); // Ensure client isn't null _ = _appClient ?? throw new System.NullReferenceException("Graph has not been initialized for app-only auth"); return _appClient.Users .Request() .Select(u => new { // Only request specific properties u.DisplayName, u.Id, u.Mail }) // Get at most 25 results .Top(25) // Sort by display name .OrderBy("DisplayName") .GetAsync(); }
Replace the empty
ListUsersAsync
function in Program.cs with the following.async Task ListUsersAsync() { try { var userPage = await GraphHelper.GetUsersAsync(); // Output each users's details foreach (var user in userPage.CurrentPage) { Console.WriteLine($"User: {user.DisplayName ?? "NO NAME"}"); Console.WriteLine($" ID: {user.Id}"); Console.WriteLine($" Email: {user.Mail ?? "NO EMAIL"}"); } // If NextPageRequest is not null, there are more users // available on the server // Access the next page like: // userPage.NextPageRequest.GetAsync(); var moreAvailable = userPage.NextPageRequest != null; Console.WriteLine($"\nMore users available? {moreAvailable}"); } catch (Exception ex) { Console.WriteLine($"Error getting users: {ex.Message}"); } }
Run the app, sign in, and choose option 4 to list users.
Please choose one of the following options: 0. Exit 1. Display access token 2. List my inbox 3. Send mail 4. List users (requires app-only) 5. Make a Graph call 4 User: Adele Vance ID: 05fb57bf-2653-4396-846d-2f210a91d9cf Email: AdeleV@contoso.com User: Alex Wilber ID: a36fe267-a437-4d24-b39e-7344774d606c Email: AlexW@contoso.com User: Allan Deyoung ID: 54cebbaa-2c56-47ec-b878-c8ff309746b0 Email: AllanD@contoso.com User: Bianca Pisani ID: 9a7dcbd0-72f0-48a9-a9fa-03cd46641d49 Email: NO EMAIL User: Brian Johnson (TAILSPIN) ID: a8989e40-be57-4c2e-bf0b-7cdc471e9cc4 Email: BrianJ@contoso.com ... More users available? True
Code explained
Consider the code in the GetUsersAsync
function. It is very similar to the code in GetInboxAsync
:
- It gets a collection of users
- It uses
Select
to request specific properties - It uses
Top
to limit the number of users returned - It uses
OrderBy
to sort the response
The key difference is that this code uses the _appClient
, not the _userClient
. Both clients use the same syntax and request builders, but were configured with different credentials.
Optional: add your own code
In this section you will add your own Microsoft Graph capabilities to the application. This could be a code snippet from Microsoft Graph documentation or Graph Explorer, or code that you created. This section is optional.
Update the app
Open ./GraphHelper.cs and add the following function to the GraphHelper class.
// This function serves as a playground for testing Graph snippets // or other code public async static Task MakeGraphCallAsync() { // INSERT YOUR CODE HERE // Note: if using _appClient, be sure to call EnsureGraphForAppOnlyAuth // before using it. // EnsureGraphForAppOnlyAuth(); }
Replace the empty
MakeGraphCallAsync
function in Program.cs with the following.async Task MakeGraphCallAsync() { await GraphHelper.MakeGraphCallAsync(); }
Choose an API
Find an API in Microsoft Graph you'd like to try. For example, the Create event API. You can use one of the examples in the API documentation, or you can customize an API request in Graph Explorer and use the generated snippet.
Configure permissions
Check the Permissions section of the reference documentation for your chosen API to see which authentication methods are supported. Some APIs don't support app-only, or personal Microsoft accounts, for example.
- To call an API with user authentication (if the API supports user (delegated) authentication), add the required permission scope in appsettings.json.
- To call an API with app-only authentication (if the API supports it), add the required permission scope in the Azure AD admin center.
Add your code
Copy your code into the MakeGraphCallAsync
function in GraphHelper.cs. If you're copying a snippet from documentation or Graph Explorer, be sure to rename the GraphServiceClient
to the appropriate client: _userClient
or _appClient
.
Congratulations!
You've completed the .NET Microsoft Graph tutorial. Now that you have a working app that calls Microsoft Graph, you can experiment and add new features. Visit the Overview of Microsoft Graph to see all of the data you can access with Microsoft Graph.
.NET samples
Have an issue with this section? If so, please give us some feedback so we can improve this section.