Calling the Microsoft Graph API from WinUI

This post is part of the C# Advent Calendar 2021. Be sure to check out all the other great posts there this month!

The Microsoft Graph enables developer to query information from Microsoft 365, including data about users, mail, Teams, OneDrive, notes, and lots more. I’ve been exploring the user and teamwork APIs recently, but in this introduction, we will explore how to authenticate and retrieve some user attributes for the authenticated user account.

We will create a WinUI application with the Windows App SDK, C#, .NET, and the .NET Graph SDK that will authenticate a Microsoft Account and display the name & email address for the current user.

Start by installing the Visual Studio extension for the Windows App SDK to add the project templates added to your IDE. Complete instructions for getting started with the latest SDK can be found here. Next, create a new Blank App, Packaged (WinUI in Desktop) project in Visual Studio. I am using Visual Studio 2022, but 2019 is also supported:

winui_graphsdk_01

Figure 1 – Creating a new WinUI project

After the project has been created, it’s always a good practice to run it to make sure things are working out of the box. Now we will add the NuGet packages needed to build our WinUI Graph app:

  • Azure.Identity – Used for interactive MSAL authentication
  • Microsoft.Extensions.DependencyInjection – Our DI container of choice for this app
  • Microsoft.Graph – The .NET Graph SDK package
  • Microsoft.Toolkit.Mvvm – A lightweight, open source MVVM framework

winui_graphsdk_02

Figure 2 – Installing the Microsoft.Toolkit.Mvvm package

Install the latest stable version of each of these packages and build the project again. We’re going to start building the app by creating a GraphService class and an IGraphService interface with one method, GetMyDetailsAsync().

public interface IGraphService
{
     Task<User> GetMyDetailsAsync();
}

The method will return a Task of Microsoft.Graph.User. We’ll get to the implementation in a moment, but first we will create an Initialize() method that will be called in the constructor. This is where the authentication code is executed.

private readonly string[] _scopes = new[] { "User.Read" };
private const string TenantId = "<your tenant id here>";
private const string ClientId = "<your client id here>";
private GraphServiceClient _client;

public GraphService()
{
     Initialize();
}

private void Initialize()
{
     var options = new InteractiveBrowserCredentialOptions
     {
         TenantId = TenantId,
         ClientId = ClientId,
         AuthorityHost = AzureAuthorityHosts.AzurePublicCloud,
         RedirectUri = new Uri("http://localhost"),
     };

    var interactiveCredential = new InteractiveBrowserCredential(options);

    _client = new GraphServiceClient(interactiveCredential, _scopes);
}

Using a TenantId in the authentication is only necessary if you want to restrict authentication to a single tenant. To read more about using Azure.Identity and MSAL, check out the docs here. The “User.Read” scope is required to access Graph data for the User object. You can read a complete list of Graph permissions here. The other aspect of using these permissions within your application is that you must have an App Registration in Azure with each required scope granted to the app in the registration. Follow these steps (under Option 2) to add your App Registration to your Azure account in the portal. This is where you will find your ClientId to enter above. Desktop applications will always use “http://localhost” as the RedirectUri.

Now we’re ready to create the implementation to get our User object.

public async Task<User> GetMyDetailsAsync()
{
     try
     {
         var user = await _client.Me.Request().GetAsync();
         return user;
     }
     catch (Exception ex)
     {
         Console.WriteLine($"Error loading user details: {ex}");
         return null;
     }
}

The code here is straightforward. Using the GraphServiceClient’s fluent API, we’re requesting “Me” to be returned asynchronously. “Me” will always return a User object for the current authenticated user.

Next, create a MainViewModel class, inheriting from ObservableObject in the MVVM Toolkit. This is the ViewModel for the MainWindow that was created as the main window by the WinUI project template. Use this code for MainViewModel.

public class MainViewModel : ObservableObject
{
     private string _userName;
     private string _email;

    public MainViewModel()
     {
         LoadUserDetailsCommand = new AsyncRelayCommand(LoadUserDetails);
     }

    public async Task LoadUserDetails()
     {
         var graphService = Ioc.Default.GetService<IGraphService>();
         var user = await graphService.GetMyDetailsAsync();
         UserName = user.DisplayName;
         Email = user.Mail;
     }

    public string UserName
     {
         get { return _userName; }
         set { SetProperty(ref _userName, value, nameof(UserName)); }
     }

    public string Email
     {
         get { return _email; }
         set { SetProperty(ref _email, value, nameof(Email)); }
     }

    public IAsyncRelayCommand LoadUserDetailsCommand { get; set; }
}

The ViewModel has properties to expose the UserName and Email that will be retrieved from the IGraphService call when LoadUserDetails is called and the service is fetched from the DI container. Now let’s set up the DI container in App.xaml.cs in the constructor after InitializeComponent().

Ioc.Default.ConfigureServices
         (new ServiceCollection()
             .AddSingleton<IGraphService, GraphService>()
             .AddSingleton<MainViewModel>()
             .BuildServiceProvider()
         );

This is registering GraphService and MainViewModel as singletons in the container. Any call to GetService will fetch the same instance. This works for us because we will only have one MainWindow and we only want to authenticate once during the lifetime of the application.

It’s finally time to work on the UI. Start by opening MainWindow.xaml and use the following markup at the root of the Window, replacing the existing controls.

<Grid x:Name="MainGrid" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="12">
     <Grid.RowDefinitions>
         <RowDefinition Height="Auto"/>
         <RowDefinition Height="Auto"/>
         <RowDefinition Height="Auto"/>
         <RowDefinition Height="Auto"/>
         <RowDefinition Height="*"/>
     </Grid.RowDefinitions>
     
     <TextBlock Text="User name:" Margin="4" Grid.Row="0"/>
     <TextBox Text="{Binding Path=UserName}" Width="200"
              Margin="4" Grid.Row="1" IsReadOnly="True"/>
     <TextBlock Text="Email:" Margin="4" Grid.Row="2"/>
     <TextBox Text="{Binding Path=Email}" Width="200"
              Margin="4" Grid.Row="3" IsReadOnly="True"/>
     <Button Command="{Binding Path=LoadUserDetailsCommand}"
             Margin="4" Content="Load Data" HorizontalAlignment="Right" Grid.Row="4"/>
</Grid>

We’ve created a parent Grid named MainGrid with five rows, two TextBlock controls and two corresponding TextBoxes, and a Load Data Button. The two TextBox controls have their Text properties bound to the UserName and Email ViewModel properties, and the Button’s Command is bound to the LoadUserDetailsCommand, which calls LoadUserDetails().

Now let’s get the MainViewModel from the DI container in the MainWindow.xaml.cs code behind file and set it as the MainGrid.DataContext. This will complete our data binding for the window.

var viewModel = Ioc.Default.GetService<MainViewModel>();
MainGrid.DataContext = viewModel;

That’s it. You’re ready to run the app. When you click Load Data, you should be prompted to log in to a Microsoft account and accept the scopes required by the app.

winui_graphsdk_04 winui_graphsdk_05

Figure 3 & 4 – Logging in to access the Graph API

Once the login is complete, you should see your username and email address populated in the text fields. We’ve done it! And notice how the WinUI window and controls pick up your Windows theme and other UI appearance without any extra markup or code required. I’m using the dark theme in Windows 11, and my app is as well.

winui_graphsdk_06

Figure 5 – Displaying the user info in our app

You can do so much more with the Graph API, using the .NET SDK or the REST APIs. Be sure to explore the docs to see what data you might want to leverage in your own apps. You can also test your API calls with the Microsoft Graph Explorer site. To learn more about WinUI, you can also check out my book from Packt Publishing, Learn WinUI 3.

Get the source code for this WinUI app on GitHub to get started with WinUI and the Graph SDK on your own.

Happy coding and happy holidays!

Dew Dump – June 18, 2020 (#3217)

Another dump of less-than-perfectly sorted links today. Back to normal service on Monday!

Top Links

Web & Cloud Development

XAML, UWP & Xamarin

Visual Studio & .NET

Design, Methodology & Testing

Mobile, IoT & Game Development

Podcasts, Screencasts & Videos

Community & Events

Database

PowerShell

Miscellaneous

More Link Collections

Latest Cloud News: Azure Bastion, .NET 5, Hololens 2, and more! (Jun 15, 2020 – Build5Nines Weekly) (Chris Pietschmann)

Adventures in Technical Editing – Three Recent Packt Book Review Projects

2019 was a busy year for me, as evidenced by the relative inactivity on my other blogs:

One of the activities that limited my 2019 blogging time was serving as a technical reviewer for three different .NET related books from Packt Publishing. All three of these books were released in the last few weeks.

Hands-On Parallel Programming with C# 8 and .NET Core 3

This book, written by Shakti Tanwar, is intended for experienced .NET developers who want to build a deep understanding of parallel and async programming with C# and .NET Core. Most of the concepts here apply just as well to .NET Framework developers, so I wouldn’t shy away from this one if you’re not using .NET Core in your projects.

I use async/await, the TPL and parallel programming concepts quite a bit in my daily work, and I still learned quite a bit from this book. I definitely recommend it if you want to build some degree of parallelism into your applications.

Learn ASP.NET Core 3

The 2nd edition book, written by Kenneth Yamikani Fukizi, Jason De Oliveira, and Michel Bruchet, details what you need to get up to speed with .NET Core 3, ASP.NET Core 3 and Entity Framework Core to build modern web applications while leveraging Microsoft Azure along the way.

The authors touch on a little bit of Blazor, one of today’s hottest .NET topics, and give some great advice for building, testing and deploying web applications with ASP.NET Core 3. If you’re familiar with .NET and ready to get into ASP.NET Core, this Packt book provides some good foundations.

C# 8 and .NET Core 3 Projects Using Azure

This second edition book by Paul Michaels, Dirk Strauss, and Jas Rademeyer is written in a fun & useful format. Each chapter is a stand-alone project that drills down into an aspect of C# and/or .NET Core development, and all of the code can is available to readers to try for themselves.

Readers will learn things like Entity Framework Core, rich UWP app development, Azure Functions, ASP.NET Core, and lots more. Some chapters will be useful to any developer, but the majority of the topics here will be most useful to devs with some .NET experience. I like this one and have recommended it to the developers on my team.

Wrapping Up

Let me know what you think of these books. Have you read any of them? What is on your reading list for 2020?

Happy learning!