© The Author(s), under exclusive license to APress Media, LLC, part of Springer Nature 2022
S. HoeflingGetting Started with the Uno Platform and WinUI 3https://doi.org/10.1007/978-1-4842-8248-9_14

14. Microsoft Graph and Dashboard Menu

Skye Hoefling1  
(1)
Rochester, NY, USA
 

In the previous chapter, we implemented the full-stack solution for retrieving data from OneDrive and displaying it on the MyFilesPage . We are going to take some of those concepts and update the Dashboard menu to include personalized information for the user’s email and name in the left corner.

Retrieving the personalized information is much simpler than loading the OneDrive files, so we will not be creating any service layer or additional Dependency Injection objects. In this chapter we will be calling into the graph right from the view model.

Tip

This chapter demonstrates that you do not always need to add API calls to a service layer. If you have a set of simple APIs, it is valid and sometimes easier to invoke them from the view model. Always evaluate your situation and make the best decision for your project. It is okay to mix and match these concepts.

In this chapter we will be updating the DashboardPage and the DashboardViewModel. We will start from the bottom of the stack and work our way up to the presentation layer.

DashboardViewModel

Earlier in this book, we created the DashboardViewModel and do not have much of any implementation. The DashboardPage has the user’s name and email address hard-coded. We will be updating this to pull the actual user display name and email from the Microsoft Graph . In the last chapter, we already added the necessary NuGet packages to integrate with the Microsoft Graph, so we can jump right into the implementation.

We need to complete the following steps to finish our implementation:
  • Injecting ILogger to the constructor

  • Public properties for data binding

  • Microsoft Graph invocations

  • Implementing IInitialize

Implement the Constructor

We will need an instance of the ILogger to handle logging throughout this class . Update the constructor to inject an instance of it and save it to a local variable. See constructor code in Listing 14-1.
public class DashboardViewModel
{
  ILogger logger;
  public DashboardViewModel(ILogger<DashboardViewModel> logger)
  {
    this.logger = logger;
  }
}
Listing 14-1

DashboardViewModel constructor implementation

Note

In Listing 14-1 we resolve the ILogger by using ILogger<DashboardViewModel>. This is the standard way to resolve any ILogger implementation using the Microsoft Logging library.

Public Properties

In our MVVM application, the public properties are used for data binding to the view or page. Before we can add our properties, we need to update the class definition to inherit from ObservableObject . This will give us access to the SetProperty() method, which we will use to notify the view of changes. See the updated class definition in Listing 14-2.
public DashboardViewModel : ObservableObject
{
  // omitted code
}
Listing 14-2

DashboardViewModel updated class definition to include ObservableObject

We can now add our public properties Name and Email. Following the public property data binding convention, the setter will use the SetProperty() method to notify the view that there is a change. See the property code snippet in Listing 14-3.
string name;
public string Name
{
  get => name;
  set => SetProperty(ref name, value);
}
string email;
public string Email
{
  get => email;
  set => SetProperty(ref email, value);
}
Listing 14-3

DashboardViewModel public property implementations

Note

When using the SetProperty() method to notify the user interface, you must pass the primitive variable as a parameter using the ref keyword. This ensures that the primitive is passed by reference instead of passed by value.

Microsoft Graph Integration

To load data from the Microsoft Graph , we will create a simple method that retrieves the Name and Email to be set to the properties we created in the last section. Create a method stub named LoadDataAsync() – see the code snippet in Listing 14-4.
public async Task LoadDataAsync()
{
  // TODO – add implementation
}
Listing 14-4

DashboardViewModel LoadDataAsync method stub

Before we can add our implementation of LoadDataAsync, we need to implement the IAuthenticationProvider interface, which is included in the Microsoft Graph SDK. This interface contains the AuthenticateRequestAsync method, which allows us to attach our access token to the outgoing HttpRequestMessage generated by the Microsoft Graph SDK. In the previous chapter, we implemented this interface in the GraphFileService . Our implementation in the DashboardViewModel will be very similar.

Update the class definition to inherit from IAuthenticationProvider – see the code snippet in Listing 14-5.
public class DashboardViewModel :
  ObservableObject, IAuthenticationProvider
{
  // omitted code
}
Listing 14-5

DashboardViewModel adds IAuthenticationProvider to the class definition

Next, we can add our implementation for the AuthenticateRequestAsync method. See the implementation in Listing 14-6.
public Task AuthenticateRequestAsync(HttpRequestMessage message)
{
  var token = ((App)App.Current)
    .AuthenticationResult
    ?.AccessToken;
  if (string.IsNullOrEmpty(token))
  {
    throw new Exception("No Access Token");
  }
  request.Headers.Authorization =
    new AuthenticationHeaderValue("Bearer", token);
  return Task.CompletedTask;
}
Listing 14-6

DashboardViewModel AuthenticateRequestAsync method implementation

Let’s work on our implementation of LoadDataAsync . We need to create an instance of the GraphServiceClient and then retrieve our data. Our Name property will be mapped from the DisplayName property, and the Email property will come from the UserPrincipalName . In the last chapter, we learned that we always need to create a special HttpHandler for WebAssembly (WASM) prior to creating the GraphServiceClient. See the implementation of LoadDataAsync in Listing 14-7.
public async Task LoadDataAsync()
{
  try
  {
    var httpClient = new HttpClient();
    var graphClient = new GraphServiceClient(httpClient);
    graphClient.AuthenticationProvider = this;
    var me = await graphClient
      .Me
      .Request()
      .Select(user => new
      {
        Id = user.Id,
        DisplayName = user.DisplayName,
        UserPrincipalName = user.UserPrincipalName
      })
      .GetAsync();
    if (me != null)
    {
      Name = me.DisplayName;
      Email = me.UserPrincipalName;
    }
  }
  catch (Exception ex)
  {
    logger.LogError(ex, ex.Message);
  }
}
Listing 14-7

DashboardViewModel basic implementation of the LoadDataAsync method

.NET 6 Mobile Considerations

In the last chapter while implementing the GraphFileService , we learned that if a library is not compiled against a .NET 6 mobile target such as net6.0-android or net6.0-ios , some objects may not work correctly. This is because the backward compatibility layer is very thin. To resolve this, we will be manually retrieving the JSON and deserializing it.

Update the code in LoadDataAsync where we create our request builder and generate the local variable me. See updated code in Listing 14-8.
var request = await graphClient
  .Me
  .Request()
  .Select(user => new
  {
    Id = user.Id,
    DisplayName = user.DisplayName,
    UserPrincipalName = user.UserPrincipalName
  });
#if __ANDROID__ || __IOS__ || __MACOS__
  var response = await request.GetResponseAsync();
  var data = await response.Content.ReadAsStringAsync();
  var me = JsonSerializer.Deserialize<User>(data);
#else
  var me = await request.GetAsync();
#endif
Listing 14-8

DashboardViewModel LoadDataAsync request builder snippet for .NET 6 mobile targets

IInitialize Implementation

The LoadDataAsync method will not be invoked unless there is something in place to tell it to load data when the page loads. In the previous chapter, we learned about our IInitialize interface and how to implement it on the view model and invoke it from the page. We need to add this code to both the DashboardViewModel and the code behind of the Dashboard in the Dashboard.xaml.cs file.

First, add the IInitialize to the class definition of the DashboardViewModel. See the code snippet in Listing 14-9.
public class DashboardViewModel :
  ObservableObject, IAuthenticationProvider, IInitialize
{
  // omitted code
}
Listing 14-9

DashboardViewModel class definition snippet adds IInitialize

The IInitialize interface defines the method InitializeAsync , which is where we will invoke our LoadDataAsync method from. We can guarantee this method is invoked just after the page is loaded. See InitializeAsync implementation in Listing 14-10.
public async Task InitializeAsync()
{
  await LoadDataAsync();
}
Listing 14-10

DashboardViewModel InitializeAsync method implementation

We need to make sure the IInitialize interface is properly invoked from the Dashboard.xaml.cs file, also known as the code behind. The implementation will be very similar to what we did in the previous chapter for the MyFilesPage.xaml.cs . In the code behind, we will create a ViewModel property that casts the DataContext to the type of DashboardViewModel. Then we will override the OnNavigatedTo method, which will invoke the InitializeAsync method on the IInitialize interface. See the code snippet in Listing 14-11.
public DashboardViewModel ViewModel =>
  (DashboardViewModel)DataContext;
protected override async void OnNavigatedTo(
  NavigationEventArgs e)
{
  base.OnNavigatedTo(e);
  // Existing code
  if (e.Parameter is INavigationService navigation)
  {
    this.navigation = navigation;
  }
  // New code
  if (ViewModel is IInitialize initializeViewModel)
  {
    await initializeViewModel.InitializeAsync();
  }
}
Listing 14-11

Dashboard.xaml.cs – invoke the IInitialize interface

Complete DashboardViewModel Implementation

We have completed our DashboardViewModel implementation – see the complete view model code in Listing 14-12.
public class DashboardViewModel :
  ObservableObject, IAuthenticationProvider, IInitialize
{
  ILogger logger;
  public DashboardViewModel(ILogger<DashboardViewModel> logger)
  {
    this.logger = logger;
  }
  string name;
  public string Name
  {
    get => name;
    set => SetProperty(ref name, value);
  }
  string email;
  public string Email
  {
    get => email;
    set => SetProperty(ref email, value);
  }
  public async Task LoadDataAsync()
  {
    try
    {
      var httpClient = new HttpClient();
      var graphClient = new GraphServiceClient(httpClient);
      graphClient.AuthenticationProvider = this;
      var request = await graphClient
        .Me
        .Request()
        .Select(user => new
        {
          Id = user.Id,
          DisplayName = user.DisplayName,
          UserPrincipalName = user.UserPrincipalName
        });
#if __ANDROID__ || __IOS__ || __MACOS__
      var response = await request.GetResponseAsync();
      var data = await response.Content.ReadAsStringAsync();
      var me = JsonSerializer.Deserialize<User>(data);
#else
      var me = await request.GetAsync();
#endif
      if (me != null)
      {
        Name = me.DisplayName;
        Email = me.UserPrincipalName;
      }
    }
    catch (Exception ex)
    {
      logger.LogError(ex, ex.Message);
    }
  }
  public Task AuthenticateRequestAsync(
    HttpRequestMessage message)
  {
    var token = ((App)App.Current)
      .AuthenticationResult
      ?.AccessToken;
    if (string.IsNullOrEmpty(token))
    {
      throw new Exception("No Access Token");
    }
    request.Headers.Authorization =
      new AuthenticationHeaderValue("Bearer", token);
    return Task.CompletedTask;
  }
  public async Task InitializeAsync()
  {
    await LoadDataAsync();
  }
}
Listing 14-12

DashboardViewModel complete implementation

Dashboard Changes

We already have the Dashboard XAML code implemented and only need to update the name and email TextBlock controls to bind to the DashboardViewModel. Find the TextBlock that has the display name in it and update the Text property to bind to the Name property on the DashboardViewModel. See the code snippet in Listing 14-13.
<TextBlock
  Text="{Binding Name}"
  FontSize="20"
  skia:HorizontalAlignment="Center"
  HorizontalAlignment="Center" />
Listing 14-13

Dashboard display name data binding snippet

Next, add data binding to the email TextBlock, which should be the next control in the XAML code. Update the Text property to bind to the Email property on the DashboardViewModel. See the code snippet in Listing 14-14.
<TextBlock
  Text="{Binding Email}"
  FontSize="18"
  skia:HorizontalAlignment="Center"
  HorizontalAlignment="Center" />
Listing 14-14

Dashboard email data binding snippet

User Interface Testing

All the code is completed, and it is time to test the various platforms. Screenshots will have the email address omitted. See screenshots of running application in Figure 14-1 for Windows, Figure 14-2 for WASM, Figure 14-3 for WPF, Figure 14-4 for Linux, Figure 14-5 for Android, Figure 14-6 for iOS, and Figure 14-7 for macOS.

Windows

A screenshot depicts the windows application, which exhibits a name and an email address in the dashboard and has some options, one of which is my files to upload or create a new file.

Figure 14-1

Windows application with display name and email in the dashboard

WebAssembly (WASM)

A webpage screenshot depicts the web assembly application, which exhibits a name and an email address in the dashboard and has some options, upload and create a new file.

Figure 14-2

WebAssembly (WASM) application with display name and email in the dashboard

WPF

A screenshot depicts the W P F application, which displays a name and an email address in the dashboard and has some options, my files to upload and create a new file.

Figure 14-3

WPF application with display name and email in the dashboard

GTK

A screenshot depicts the G T K application in which the filesystem root, trash, file system, and home are at the far left. In the dashboard, a name and an email address are displayed, along with some options.

Figure 14-4

GTK application with display name and email in the dashboard

Android

A screenshot depicts a mobile screen with an android application that exhibits a name and an email address and options such as my files, recent, shared, and signs out.

Figure 14-5

Android application with display name and email in the dashboard

iOS

A screenshot depicts a mobile screen with an i O S application that displays a name, an email address, and options such as my files, recent, shared, and sign-out.

Figure 14-6

iOS application with display name and email in the dashboard

macOS

A screenshot depicts a mac O S application that displays a name, email address, and options such as my files, recent, shared, and sign out. My files are selected and no data found is exhibited.

Figure 14-7

macOS application with display name and email in the dashboard

Conclusion

In this chapter we built on the Microsoft Graph concepts we learned in Chapter 13 while we added more personalization to the dashboard menu. If you had any trouble implementing the code, go and download the sample code before moving on to the next chapter: https://github.com/SkyeHoefling/UnoDrive/tree/main/Chapter%2014 .

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.221.245.196