Erstellen von Webservern-WebAssembly-Apps mit Microsoft Graph
In diesem Lernprogramm erfahren Sie, wie Sie eine clientseitige Webserversauder-WebAssembly-App erstellen, die die Microsoft Graph-API zum Abrufen von Kalenderinformationen für einen Benutzer verwendet.
Tipp
Wenn Sie es vorziehen, nur das abgeschlossene Lernprogramm herunterzuladen, können Sie das GitHub Repository herunterladen oder klonen. Anweisungen zum Konfigurieren der App mit einer App-ID und einem geheimen Schlüssel finden Sie in der README-Datei im Demoordner .
Voraussetzungen
Bevor Sie mit diesem Lernprogramm beginnen, sollten Sie das .NET SDK auf Ihrem Entwicklungscomputer installiert haben. Wenn Sie nicht über das SDK verfügen, besuchen Sie den vorherigen Link, um Downloadoptionen zu erhalten.
Sie sollten auch über ein persönliches Microsoft-Konto mit einem Postfach auf Outlook.com oder ein Microsoft-Geschäfts-, Schul- oder Unikonto verfügen. Wenn Sie kein Microsoft-Konto haben, gibt es einige Optionen, um ein kostenloses Konto zu erhalten:
- Sie können sich für ein neues persönliches Microsoft-Konto registrieren.
- Sie können sich für das Microsoft 365-Entwicklerprogramm registrieren, um ein kostenloses Microsoft 365 Abonnement zu erhalten.
Hinweis
Dieses Lernprogramm wurde mit .NET SDK Version 5.0.302 geschrieben. Die Schritte in diesem Handbuch funktionieren möglicherweise mit anderen Versionen, die jedoch nicht getestet wurden.
Feedback
Bitte geben Sie Feedback zu diesem Lernprogramm im GitHub Repository.
Erstellen einer Webserverwebassembly-App
Beginnen Sie mit dem Erstellen einer Webanwendung für Die WebAssembly.
Öffnen Sie die Befehlszeilenschnittstelle (CLI) in einem Verzeichnis, in dem Sie das Projekt erstellen möchten. Führen Sie den folgenden Befehl aus.
dotnet new blazorwasm --auth SingleOrg -o GraphTutorialDer
--auth SingleOrgParameter bewirkt, dass das generierte Projekt die Konfiguration für die Authentifizierung mit dem Microsoft Identity Platform enthält.Nachdem das Projekt erstellt wurde, überprüfen Sie, ob es funktioniert, indem Sie das aktuelle Verzeichnis in das GraphTutorial-Verzeichnis ändern und den folgenden Befehl in Ihrer CLI ausführen.
dotnet watch runÖffnen Sie Ihren Browser, und navigieren Sie zu
https://localhost:5001. Wenn alles funktioniert, sollten Sie ein "Hello, world!" sehen. Nachricht.
Wichtig
Wenn Sie eine Warnung erhalten, dass das Zertifikat für localhost nicht vertrauenswürdig ist, können Sie die .NET Core CLI verwenden, um das Entwicklungszertifikat zu installieren und ihm zu vertrauen. Anweisungen zu bestimmten Betriebssystemen finden Sie unter "HTTPS erzwingen" in ASP.NET Core.
Hinzufügen von NuGet-Paketen
Installieren Sie vor dem Fortfahren einige zusätzliche NuGet Pakete, die Sie später verwenden werden.
- Microsoft.Graph zum Aufrufen von Microsoft Graph
- TimeZoneConverter zum Übersetzen von Windows Zeitzonenbezeichnern in IANA-Bezeichner.
Führen Sie die folgenden Befehle in Der CLI aus, um die Abhängigkeiten zu installieren.
dotnet add package Microsoft.Graph --version 4.1.0 dotnet add package TimeZoneConverter
Entwerfen der App
In diesem Abschnitt erstellen Sie die grundlegende UI-Struktur der Anwendung.
Entfernen Von der Vorlage generierte Beispielseiten. Löschen Sie die folgenden Dateien.
- ./Pages/Counter.razor
- ./Pages/FetchData.razor
- ./Shared/SurveyPrompt.razor
- ./wwwroot/sample-data/weather.json
Öffnen Sie ./wwwroot/index.html , und fügen Sie den folgenden Code direkt vor dem schließenden
</body>Tag hinzu.<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js" integrity="sha384-B4gt1jrGC7Jh4AgTPSdUtOBvfO8shuf57BaghqFfPlYxofvL8/KUEfYiJOMMV+rV" crossorigin="anonymous"></script>Dadurch werden die JavaScript-Dateien "Bootstrap " hinzugefügt.
Öffnen Sie ./wwwroot/css/app.css , und fügen Sie den folgenden Code hinzu.
.nav-profile-photo { width: 36px; }Öffnen Sie "./Shared/NavMenu.razor" , und ersetzen Sie den Inhalt durch Folgendes.
<div class="top-row pl-4 navbar navbar-dark"> <a class="navbar-brand" href="">GraphTutorial</a> <button class="navbar-toggler" @onclick="ToggleNavMenu"> <span class="navbar-toggler-icon"></span> </button> </div> <div class="@NavMenuCssClass" @onclick="ToggleNavMenu"> <ul class="nav flex-column"> <li class="nav-item px-3"> <NavLink class="nav-link" href="" Match="NavLinkMatch.All"> <span class="oi oi-home" aria-hidden="true"></span> Home </NavLink> </li> <li class="nav-item px-3"> <NavLink class="nav-link" href="calendar"> <span class="oi oi-calendar" aria-hidden="true"></span> Calendar </NavLink> </li> </ul> </div> @code { private bool collapseNavMenu = true; private string NavMenuCssClass => collapseNavMenu ? "collapse" : null; private void ToggleNavMenu() { collapseNavMenu = !collapseNavMenu; } }Öffnen Sie ./Pages/Index.razor , und ersetzen Sie den Inhalt durch Folgendes.
@page "/" <div class="jumbotron"> <h1>Blazor Client-side Graph Tutorial</h1> <p class="lead">This sample app shows how to use the Microsoft Graph API to access a user's data from a Blazor client-side app</p> <AuthorizeView> <Authorized> <h4>Welcome @context.User.Identity.Name!</h4> <p>Use the navigation bar on the left to get started.</p> </Authorized> <NotAuthorized> <a class="btn btn-primary btn-large" href="authentication/login">Click here to sign in</a> </NotAuthorized> </AuthorizeView> </div>Open ./Shared/LoginDisplay.razor and replace its contents with the following.
@using Microsoft.AspNetCore.Components.Authorization @using Microsoft.AspNetCore.Components.WebAssembly.Authentication @inject NavigationManager Navigation @inject SignOutSessionStateManager SignOutManager <AuthorizeView> <Authorized> <a class="text-decoration-none" data-toggle="dropdown" href="#" role="button"> <img src="/img/no-profile-photo.png" class="nav-profile-photo rounded-circle align-self-center mr-2"> </a> <div class="dropdown-menu dropdown-menu-right"> <h5 class="dropdown-item-text mb-0">@context.User.Identity.Name</h5> <p class="dropdown-item-text text-muted mb-0">placeholder@contoso.com</p> <div class="dropdown-divider"></div> <button class="dropdown-item" @onclick="BeginLogout">Log out</button> </div> </Authorized> <NotAuthorized> <a href="authentication/login">Log in</a> </NotAuthorized> </AuthorizeView> @code{ private async Task BeginLogout(MouseEventArgs args) { await SignOutManager.SetSignOutState(); Navigation.NavigateTo("authentication/logout"); } }Erstellen Sie ein neues Verzeichnis im Verzeichnis "./wwwroot " mit dem Namen "img". Fügen Sie in diesem Verzeichnis eine Bilddatei mit dem Namen no-profile-photo.png Ihrer Wahl hinzu. Dieses Bild wird als Foto des Benutzers verwendet, wenn der Benutzer kein Foto in Microsoft Graph hat.
Tipp
Sie können das in diesen Screenshots verwendete Bild aus GitHub herunterladen.
Speichern Sie alle Änderungen, und aktualisieren Sie die Seite.

Registrieren der App im Portal
In dieser Übung erstellen Sie eine neue Azure AD Webanwendungsregistrierung mithilfe des Azure Active Directory Admin Centers.
Öffnen Sie einen Browser, und navigieren Sie zum Azure Active Directory Admin Center. Melden Sie sich mit einem persönlichen Konto (auch: Microsoft-Konto) oder einem Geschäfts- oder Schulkonto an.
Wählen Sie in der linken Navigationsleiste Azure Active Directory aus, und wählen Sie dann App-Registrierungen unter Verwalten aus.

Wählen Sie Neue Registrierung aus. Legen Sie auf der Seite Anwendung registrieren die Werte wie folgt fest.
- Legen Sie Name auf
Blazor Graph Tutorialfest. - Legen Sie Unterstützte Kontotypen auf Konten in allen Organisationsverzeichnissen und persönliche Microsoft-Konten fest.
- Legen Sie unter "Umleitungs-URI" die erste Dropdownliste auf eine Einzelseitenanwendung (Single-Page Application, SPA) fest, und legen Sie den Wert auf
https://localhost:5001/authentication/login-callback.

- Legen Sie Name auf
Wählen Sie Registrieren aus. Kopieren Sie den Wert der Anwendungs-ID (Client-ID) auf der Seite Graph Lernprogramm, und speichern Sie ihn. Sie benötigen ihn im nächsten Schritt.

Hinzufügen der Azure AD-Authentifizierung
In dieser Übung erweitern Sie die Anwendung aus der vorherigen Übung, um die Authentifizierung mit Azure AD zu unterstützen. Dies ist notwendig, um das erforderliche OAuth-Zugriffstoken zum Aufruf der Microsoft Graph-API abzurufen.
Öffnen Sie ./wwwroot/appsettings.json. Fügen Sie eine Eigenschaft hinzu
GraphScopes, und aktualisieren Sie dieAuthoritywerteClientIdso, dass sie den folgenden Werten entsprechen.{ "AzureAd": { "Authority": "https://login.microsoftonline.com/common", "ClientId": "YOUR_APP_ID_HERE", "ValidateAuthority": true }, "GraphScopes": "User.Read;MailboxSettings.Read;Calendars.ReadWrite" }Ersetzen Sie
YOUR_APP_ID_HEREdies durch die Anwendungs-ID aus Ihrer App-Registrierung.Wichtig
Wenn Sie die Quellcodeverwaltung wie Git verwenden, wäre es jetzt ein guter Zeitpunkt, die Datei "appsettings.json " aus der Quellcodeverwaltung auszuschließen, um zu vermeiden, dass versehentlich Ihre App-ID offengelegt wird.
Überprüfen Sie die im
GraphScopesWert enthaltenen Bereiche.- User.Read ermöglicht der Anwendung, das Profil und Foto des Benutzers abzurufen.
- MailboxSettings.Read ermöglicht der Anwendung das Abrufen von Postfacheinstellungen, die die bevorzugte Zeitzone des Benutzers enthalten.
- Calendars.ReadWrite ermöglicht der Anwendung das Lesen und Schreiben in den Kalender des Benutzers.
Implementieren der Anmeldung
An diesem Punkt hat die .NET Core-Projektvorlage den Code zum Aktivieren der Anmeldung hinzugefügt. In diesem Abschnitt fügen Sie jedoch zusätzlichen Code hinzu, um die Benutzererfahrung zu verbessern, indem Sie Informationen von Microsoft Graph zur Identität des Benutzers hinzufügen.
Öffnen Sie ./Pages/Authentication.razor , und ersetzen Sie den Inhalt durch Folgendes.
@page "/authentication/{action}" @using Microsoft.AspNetCore.Components.WebAssembly.Authentication <RemoteAuthenticatorView Action="@Action" LogInFailed="LogInFailedFragment" /> @code{ [Parameter] public string Action { get; set; } private static RenderFragment LogInFailedFragment(string message) { return builder => { builder.OpenElement(0, "div"); builder.AddAttribute(1, "class", "alert alert-danger"); builder.AddAttribute(2, "role", "alert"); builder.OpenElement(3, "p"); builder.AddContent(4, "There was an error trying to log you in."); builder.CloseElement(); if (!string.IsNullOrEmpty(message)) { builder.OpenElement(5, "p"); builder.AddContent(6, $"Error: {message}"); builder.CloseElement(); } builder.CloseElement(); }; } }Dadurch wird die Standardfehlermeldung ersetzt, wenn bei der Anmeldung keine vom Authentifizierungsprozess zurückgegebene Fehlermeldung angezeigt wird.
Erstellen Sie ein neues Verzeichnis im Stammverzeichnis des Projekts mit dem Namen Graph.
Erstellen Sie eine neue Datei im Verzeichnis "./Graph" mit dem Namen "GraphUserAccountFactory.cs", und fügen Sie den folgenden Code hinzu.
using System.Security.Claims; using System.Threading.Tasks; using Microsoft.AspNetCore.Components.WebAssembly.Authentication; using Microsoft.AspNetCore.Components.WebAssembly.Authentication.Internal; using Microsoft.Extensions.Logging; using Microsoft.Graph; namespace GraphTutorial.Graph { // Extends the AccountClaimsPrincipalFactory that builds // a user identity from the identity token. // This class adds additional claims to the user's ClaimPrincipal // that hold values from Microsoft Graph public class GraphUserAccountFactory : AccountClaimsPrincipalFactory<RemoteUserAccount> { private readonly IAccessTokenProviderAccessor accessor; private readonly ILogger<GraphUserAccountFactory> logger; public GraphUserAccountFactory(IAccessTokenProviderAccessor accessor, ILogger<GraphUserAccountFactory> logger) : base(accessor) { this.accessor = accessor; this.logger = logger; } public async override ValueTask<ClaimsPrincipal> CreateUserAsync( RemoteUserAccount account, RemoteAuthenticationUserOptions options) { // Create the base user var initialUser = await base.CreateUserAsync(account, options); // If authenticated, we can call Microsoft Graph if (initialUser.Identity.IsAuthenticated) { try { // Add additional info from Graph to the identity await AddGraphInfoToClaims(accessor, initialUser); } catch (AccessTokenNotAvailableException exception) { logger.LogError($"Graph API access token failure: {exception.Message}"); } catch (ServiceException exception) { logger.LogError($"Graph API error: {exception.Message}"); logger.LogError($"Response body: {exception.RawResponseBody}"); } } return initialUser; } private async Task AddGraphInfoToClaims( IAccessTokenProviderAccessor accessor, ClaimsPrincipal claimsPrincipal) { // TEMPORARY: Get the token and log it var result = await accessor.TokenProvider.RequestAccessToken(); if (result.TryGetToken(out var token)) { logger.LogInformation($"Access token: {token.Value}"); } } } }Diese Klasse erweitert die AccountClaimsPrincipalFactory-Klasse und überschreibt die
CreateUserAsyncMethode. Derzeit protokolliert diese Methode nur das Zugriffstoken zu Debugzwecken. Sie implementieren die Microsoft Graph-Aufrufe später in dieser Übung.Öffnen Sie "./Program.cs" , und fügen Sie die folgenden
usingAnweisungen am Anfang der Datei hinzu.using Microsoft.AspNetCore.Components.WebAssembly.Authentication; using GraphTutorial.Graph;Ersetzen Sie innerhalb
Maindes vorhandenenbuilder.Services.AddMsalAuthenticationAufrufs durch Folgendes.builder.Services.AddMsalAuthentication<RemoteAuthenticationState, RemoteUserAccount>(options => { var scopes = builder.Configuration.GetValue<string>("GraphScopes"); if (string.IsNullOrEmpty(scopes)) { Console.WriteLine("WARNING: No permission scopes were found in the GraphScopes app setting. Using default User.Read."); scopes = "User.Read"; } foreach(var scope in scopes.Split(';')) { Console.WriteLine($"Adding {scope} to requested permissions"); options.ProviderOptions.DefaultAccessTokenScopes.Add(scope); } builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication); }) .AddAccountClaimsPrincipalFactory<RemoteAuthenticationState, RemoteUserAccount, GraphUserAccountFactory>();Überlegen Sie, was dieser Code bewirkt.
- Es lädt den Wert von
GraphScopes" appsettings.json " und fügt jeden Bereich zu den Standardbereichen hinzu, die vom MSAL-Anbieter verwendet werden. - Er ersetzt die vorhandene Kontofactory durch die GraphUserAccountFactory-Klasse .
- Es lädt den Wert von
Speichern Sie die Änderungen, und starten Sie die App neu. Verwenden Sie den Link "Anmelden ", um sich anzumelden. Überprüfen und akzeptieren Sie die angeforderten Berechtigungen.
Die App wird mit einer Willkommensnachricht aktualisiert. Greifen Sie auf die Entwicklertools Ihres Browsers zu, und überprüfen Sie die Konsolenregisterkarte . Die App protokolliert das Zugriffstoken.

Benutzerdetails abrufen
Sobald sich der Benutzer angemeldet hat, können Sie dessen Informationen über Microsoft Graph abrufen. In diesem Abschnitt verwenden Sie Informationen von Microsoft Graph, um dem ClaimsPrincipal des Benutzers zusätzliche Ansprüche hinzuzufügen.
Erstellen Sie eine neue Datei im Verzeichnis "./Graph" mit dem Namen "GraphClaimsPrincipalExtensions.cs", und fügen Sie den folgenden Code hinzu.
using Microsoft.Graph; using System; using System.IO; using System.Security.Claims; namespace GraphTutorial { public static class GraphClaimTypes { public const string DateFormat = "graph_dateformat"; public const string Email = "graph_email"; public const string Photo = "graph_photo"; public const string TimeZone = "graph_timezone"; public const string TimeFormat = "graph_timeformat"; } // Helper methods to access Graph user data stored in // the claims principal public static class GraphClaimsPrincipalExtensions { public static string GetUserGraphDateFormat(this ClaimsPrincipal claimsPrincipal) { var claim = claimsPrincipal.FindFirst(GraphClaimTypes.DateFormat); return claim == null ? null : claim.Value; } public static string GetUserGraphEmail(this ClaimsPrincipal claimsPrincipal) { var claim = claimsPrincipal.FindFirst(GraphClaimTypes.Email); return claim == null ? null : claim.Value; } public static string GetUserGraphPhoto(this ClaimsPrincipal claimsPrincipal) { var claim = claimsPrincipal.FindFirst(GraphClaimTypes.Photo); return claim == null ? null : claim.Value; } public static string GetUserGraphTimeZone(this ClaimsPrincipal claimsPrincipal) { var claim = claimsPrincipal.FindFirst(GraphClaimTypes.TimeZone); return claim == null ? null : claim.Value; } public static string GetUserGraphTimeFormat(this ClaimsPrincipal claimsPrincipal) { var claim = claimsPrincipal.FindFirst(GraphClaimTypes.TimeFormat); return claim == null ? null : claim.Value; } // Adds claims from the provided User object public static void AddUserGraphInfo(this ClaimsPrincipal claimsPrincipal, User user) { var identity = claimsPrincipal.Identity as ClaimsIdentity; identity.AddClaim( new Claim(GraphClaimTypes.DateFormat, user.MailboxSettings.DateFormat)); identity.AddClaim( new Claim(GraphClaimTypes.Email, user.Mail ?? user.UserPrincipalName)); identity.AddClaim( new Claim(GraphClaimTypes.TimeZone, user.MailboxSettings.TimeZone)); identity.AddClaim( new Claim(GraphClaimTypes.TimeFormat, user.MailboxSettings.TimeFormat)); } // Converts a photo Stream to a Data URI and stores it in a claim public static void AddUserGraphPhoto(this ClaimsPrincipal claimsPrincipal, Stream photoStream) { var identity = claimsPrincipal.Identity as ClaimsIdentity; if (photoStream != null) { // Copy the photo stream to a memory stream // to get the bytes out of it var memoryStream = new MemoryStream(); photoStream.CopyTo(memoryStream); var photoBytes = memoryStream.ToArray(); // Generate a date URI for the photo var photoUri = $"data:image/png;base64,{Convert.ToBase64String(photoBytes)}"; identity.AddClaim( new Claim(GraphClaimTypes.Photo, photoUri)); } } } }Dieser Code implementiert Erweiterungsmethoden für die ClaimsPrincipal-Klasse, mit denen Sie Ansprüche mit Werten aus Microsoft Graph-Objekten abrufen und festlegen können.
Erstellen Sie eine neue Datei im Verzeichnis "./Graph" mit dem Namen "DoppelklickauthProvider.cs", und fügen Sie den folgenden Code hinzu.
using System.Net.Http; using System.Net.Http.Headers; using System.Threading.Tasks; using Microsoft.AspNetCore.Components.WebAssembly.Authentication.Internal; using Microsoft.Graph; namespace GraphTutorial.Graph { public class BlazorAuthProvider : IAuthenticationProvider { private readonly IAccessTokenProviderAccessor accessor; public BlazorAuthProvider(IAccessTokenProviderAccessor accessor) { this.accessor = accessor; } // Function called every time the GraphServiceClient makes a call public async Task AuthenticateRequestAsync(HttpRequestMessage request) { // Request the token from the accessor var result = await accessor.TokenProvider.RequestAccessToken(); if (result.TryGetToken(out var token)) { // Add the token to the Authorization header request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token.Value); } } } }Dieser Code implementiert einen Authentifizierungsanbieter für das Microsoft Graph SDK, das den vom Microsoft.AspNetCore.Components.WebAssembly.Authentication-Paket bereitgestellten IAccessTokenProviderAccessor verwendet, um Zugriffstoken abzurufen.
Erstellen Sie eine neue Datei im Verzeichnis "./Graph" mit dem Namen "GraphClientFactory.cs", und fügen Sie den folgenden Code hinzu.
using System.Net.Http; using Microsoft.AspNetCore.Components.WebAssembly.Authentication.Internal; using Microsoft.Extensions.Logging; using Microsoft.Graph; namespace GraphTutorial.Graph { public class GraphClientFactory { private readonly IAccessTokenProviderAccessor accessor; private readonly HttpClient httpClient; private readonly ILogger<GraphClientFactory> logger; private GraphServiceClient graphClient; public GraphClientFactory(IAccessTokenProviderAccessor accessor, HttpClient httpClient, ILogger<GraphClientFactory> logger) { this.accessor = accessor; this.httpClient = httpClient; this.logger = logger; } public GraphServiceClient GetAuthenticatedClient() { // Use the existing one if it's there if (graphClient == null) { // Create a GraphServiceClient using a scoped // HttpClient graphClient = new GraphServiceClient(httpClient); // Configure the auth provider graphClient.AuthenticationProvider = new BlazorAuthProvider(accessor); } return graphClient; } } }Diese Klasse erstellt einen GraphServiceClient , der mit dem Webdienste-Anbieter konfiguriert ist.
Öffnen Sie ./Program.cs , und ändern Sie die BaseAddress des neuen HttpClient in
"https://graph.microsoft.com".// HttpClient for passing into GraphServiceClient constructor builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri("https://graph.microsoft.com") });Fügen Sie den folgenden Code vor der
await builder.Build().RunAsync();Zeile hinzu.builder.Services.AddScoped<GraphClientFactory>();Dadurch wird GraphClientFactory als bereichsbezogenen Dienst hinzugefügt, den wir über die Abhängigkeitsinjektion zur Verfügung stellen können.
Öffnen Sie ./Graph/GraphUserAccountFactory.cs, und fügen Sie der Klasse die folgende Eigenschaft hinzu.
private readonly GraphClientFactory clientFactory;Aktualisieren Sie den Konstruktor so, dass er einen GraphClientFactory-Parameter verwendet und der
clientFactoryEigenschaft zuweist.public GraphUserAccountFactory(IAccessTokenProviderAccessor accessor, GraphClientFactory clientFactory, ILogger<GraphUserAccountFactory> logger) : base(accessor) { this.accessor = accessor; this.clientFactory = clientFactory; this.logger = logger; }Ersetzen Sie die vorhandene
AddGraphInfoToClaims-Funktion durch Folgendes.private async Task AddGraphInfoToClaims( IAccessTokenProviderAccessor accessor, ClaimsPrincipal claimsPrincipal) { var graphClient = clientFactory.GetAuthenticatedClient(); // Get user profile including mailbox settings // GET /me?$select=displayName,mail,mailboxSettings,userPrincipalName var user = await graphClient.Me .Request() // Request only the properties used to // set claims .Select(u => new { u.DisplayName, u.Mail, u.MailboxSettings, u.UserPrincipalName }) .GetAsync(); logger.LogInformation($"Got user: {user.DisplayName}"); claimsPrincipal.AddUserGraphInfo(user); // Get user's photo // GET /me/photos/48x48/$value var photo = await graphClient.Me .Photos["48x48"] // Smallest standard size .Content .Request() .GetAsync(); claimsPrincipal.AddUserGraphPhoto(photo); }Überlegen Sie, was dieser Code bewirkt.
- Es ruft das Profil des Benutzers ab.
- Es wird verwendet
Select, um zu begrenzen, welche Eigenschaften zurückgegeben werden.
- Es wird verwendet
- Es ruft das Foto des Benutzers ab.
- Es fordert speziell die 48 x 48-Pixel-Version des Fotos des Benutzers an.
- Die Informationen werden dem ClaimsPrincipal hinzugefügt.
- Es ruft das Profil des Benutzers ab.
Öffnen Sie "./Shared/LoginDisplay.razor", und nehmen Sie die folgenden Änderungen vor.
- Ersetzen Sie
/img/no-profile-photo.pngdurch@(context.User.GetUserGraphPhoto() ?? "/img/no-profile-photo.png"). - Ersetzen Sie
placeholder@contoso.comdurch@context.User.GetUserGraphEmail().
... <img src="@(context.User.GetUserGraphPhoto() ?? "/img/no-profile-photo.png")" class="nav-profile-photo rounded-circle align-self-center mr-2"> ... <p class="dropdown-item-text text-muted mb-0">@context.User.GetUserGraphEmail()</p> ...- Ersetzen Sie
Speichern Sie alle Änderungen, und starten Sie die App neu. Melden Sie sich bei der App an. Die App wird aktualisiert, um das Foto des Benutzers im oberen Menü anzuzeigen. Wenn Sie das Foto des Benutzers auswählen, wird ein Dropdownmenü mit dem Namen des Benutzers, der E-Mail-Adresse und der Schaltfläche " Abmelden " geöffnet.


Abrufen einer Kalenderansicht
In diesem Abschnitt integrieren Sie microsoft Graph weiter in die Anwendung, um eine Ansicht des Kalenders des Benutzers für die aktuelle Woche zu erhalten.
Abrufen einer Kalenderansicht
Erstellen Sie eine neue Datei im Verzeichnis "./Pages" mit dem Namen "Calendar.razor", und fügen Sie den folgenden Code hinzu.
@page "/calendar" @using Microsoft.Graph @using TimeZoneConverter @inject GraphTutorial.Graph.GraphClientFactory clientFactory <AuthorizeView> <Authorized> <!-- Temporary JSON dump of events --> <code>@graphClient.HttpProvider.Serializer.SerializeObject(events)</code> </Authorized> <NotAuthorized> <RedirectToLogin /> </NotAuthorized> </AuthorizeView> @code{ [CascadingParameter] private Task<AuthenticationState> authenticationStateTask { get; set; } private GraphServiceClient graphClient; private IList<Event> events = new List<Event>(); private string dateTimeFormat; }Fügen Sie den folgenden Code innerhalb des Abschnitts
@code{}hinzu.protected override async Task OnInitializedAsync() { // Get the user var user = (await authenticationStateTask).User; var graphTimeZone = user.GetUserGraphTimeZone(); dateTimeFormat = $"{user.GetUserGraphDateFormat()} {user.GetUserGraphTimeFormat()}"; // Calculate the start and end of the current week in user's time zone var startOfWeek = GetUtcStartOfWeekInTimeZone(DateTime.Today, graphTimeZone); var endOfWeek = startOfWeek.AddDays(7); graphClient = clientFactory.GetAuthenticatedClient(); // Specifies the start and end of the view on the calendar // Translates to: ?startDateTime=""&endDateTime="" var viewOptions = new List<QueryOption> { new QueryOption("startDateTime", startOfWeek.ToString("o")), new QueryOption("endDateTime", endOfWeek.ToString("o")) }; var eventPage = await graphClient.Me .CalendarView .Request(viewOptions) // Send user time zone in request so date/time in // response will be in preferred time zone .Header("Prefer", $"outlook.timezone=\"{graphTimeZone}\"") // Get max 50 per request .Top(50) // Only return fields app will use .Select(e => new { e.Subject, e.Organizer, e.Start, e.End }) // Order results chronologically .OrderBy("start/dateTime") .GetAsync(); events = eventPage.CurrentPage; } private DateTime GetUtcStartOfWeekInTimeZone(DateTime today, string timeZoneId) { // Time zone returned by Graph could be Windows or IANA style // TimeZoneConverter can take either TimeZoneInfo userTimeZone = TZConvert.GetTimeZoneInfo(timeZoneId); // Assumes Sunday as first day of week int diff = System.DayOfWeek.Sunday - today.DayOfWeek; // create date as unspecified kind var unspecifiedStart = DateTime.SpecifyKind(today.AddDays(diff), DateTimeKind.Unspecified); // convert to UTC return TimeZoneInfo.ConvertTimeToUtc(unspecifiedStart, userTimeZone); }Überlegen Sie, was dieser Code bewirkt.
- Sie ruft die Zeitzone, das Datumsformat und das Uhrzeitformat des aktuellen Benutzers aus den benutzerdefinierten Ansprüchen ab, die dem Benutzer hinzugefügt wurden.
- Es berechnet den Anfang und das Ende der aktuellen Woche in der bevorzugten Zeitzone des Benutzers.
- Sie ruft eine Kalenderansicht von Microsoft Graph für die aktuelle Woche ab.
- Es enthält den
Prefer: outlook.timezoneHeader, damit Microsoft Graph diestartEigenschaften inendder angegebenen Zeitzone zurückgibt. - Es wird
Top(50)verwendet, um bis zu 50 Ereignisse in der Antwort anzufordern. - Es wird verwendet
Select(u => new {}), um nur die von der App verwendeten Eigenschaften anzufordern. - Es wird
OrderBy("start/dateTime")verwendet, um die Ergebnisse nach Startzeit zu sortieren.
- Es enthält den
Speichern Sie alle Änderungen, und starten Sie die App neu. Wählen Sie das Kalendernavigationsleistenelement aus. Die App zeigt eine JSON-Darstellung der von Microsoft Graph zurückgegebenen Ereignisse an.
Anzeigen der Ergebnisse
Jetzt können Sie das JSON-Dump durch etwas benutzerfreundlicheres ersetzen.
Fügen Sie die folgende Funktion innerhalb des Abschnitts
@code{}hinzu.private string FormatIso8601DateTime(string iso8601DateTime) { // Load into a DateTime var dateTime = DateTime.Parse(iso8601DateTime); if (!string.IsNullOrWhiteSpace(dateTimeFormat)) { // Format it using the user's settings return dateTime.ToString(dateTimeFormat); } // Fallback to return original value return iso8601DateTime; }Dieser Code verwendet eine ISO 8601-Datumszeichenfolge und konvertiert sie in das bevorzugte Datums- und Uhrzeitformat des Benutzers.
Ersetzen Sie das
<code>Element innerhalb des<Authorized>Elements durch Folgendes.<Authorized> <h1 class="mb-3">Calendar</h1> <a href="/newevent" class="btn btn-light btn-sm mb-3">New event</a> <table class="table"> <thead> <tr> <th>Organizer</th> <th>Subject</th> <th>Start</th> <th>End</th> </tr> </thead> <tbody> @foreach(var calendarEvent in events) { <tr> <td>@calendarEvent.Organizer.EmailAddress.Name</td> <td>@calendarEvent.Subject</td> <td>@FormatIso8601DateTime(calendarEvent.Start.DateTime)</td> <td>@FormatIso8601DateTime(calendarEvent.End.DateTime)</td> </tr> } </tbody> </table> </Authorized>Dadurch wird eine Tabelle der ereignisse erstellt, die von Microsoft Graph zurückgegeben werden.
Speichern Sie die Änderungen, und starten Sie die App neu. Auf der Kalenderseite wird nun eine Tabelle mit Ereignissen gerendert.

Erstellen eines neuen Ereignisses
In diesem Abschnitt fügen Sie die Möglichkeit hinzu, Ereignisse im Kalender des Benutzers zu erstellen.
Erstellen Sie eine neue Datei im Verzeichnis "./Pages" mit dem Namen "NewEvent.razor" , und fügen Sie den folgenden Code hinzu.
@page "/newevent" @using Microsoft.Graph @inject GraphTutorial.Graph.GraphClientFactory clientFactory <AuthorizeView> <Authorized> @if (!string.IsNullOrEmpty(status)) { <div class="alert @(isError ? "alert-danger" : "alert-success")">@status</div> } <form> <div class="form-group"> <label>Subject</label> <input @bind="subject" class="form-control" /> </div> <div class="form-group"> <label>Attendees</label> <input @bind="attendees" class="form-control" /> </div> <div class="form-row"> <div class="col"> <div class="form-group"> <label>Start</label> <input @bind="start" type="datetime" class="form-control" /> </div> </div> <div class="col"> <div class="form-group"> <label>End</label> <input @bind="end" type="datetime" class="form-control" /> </div> </div> </div> <div class="form-group"> <label>Body</label> <textarea @bind="body" class="form-control"></textarea> </div> </form> <button class="btn btn-primary mr-2" @onclick="CreateEvent">Create</button> <a href="/calendar" class="btn btn-secondrary">Cancel</a> </Authorized> <NotAuthorized> <RedirectToLogin /> </NotAuthorized> </AuthorizeView>Dadurch wird der Seite ein Formular hinzugefügt, damit der Benutzer Werte für das neue Ereignis eingeben kann.
Fügen Sie den folgenden Code am Ende der Datei hinzu.
@code{ [CascadingParameter] private Task<AuthenticationState> authenticationStateTask { get; set; } private string status; private bool isError; private string userTimeZone; private string subject; private string attendees; private DateTime start = new DateTime(DateTime.Today.Ticks); private DateTime end = new DateTime(DateTime.Today.Ticks); private string body; protected override async Task OnInitializedAsync() { // Get the user's time zone var user = (await authenticationStateTask).User; userTimeZone = user.GetUserGraphTimeZone() ?? "UTC"; } private async Task CreateEvent() { // Initalize an Event object // with user input var newEvent = new Event { Subject = subject, Start = new DateTimeTimeZone { DateTime = start.ToString("o"), TimeZone = userTimeZone }, End = new DateTimeTimeZone { DateTime = end.ToString("o"), TimeZone = userTimeZone }, Body = new ItemBody { Content = body, ContentType = BodyType.Text } }; // If the user provided attendees (semicolon-delimited // list of email addresses) add them if (!string.IsNullOrEmpty(attendees)) { var attendeeList = new List<Attendee>(); var attendeeArray = attendees.Split(";"); foreach (var email in attendeeArray) { Console.WriteLine($"Adding {email}"); attendeeList.Add(new Attendee { // Set to required attendee Type = AttendeeType.Required, EmailAddress = new EmailAddress { Address = email } }); } newEvent.Attendees = attendeeList; } var graphClient = clientFactory.GetAuthenticatedClient(); try { // POST /me/events await graphClient.Me .Events .Request() .AddAsync(newEvent); isError = false; status = "Event created"; } catch (ServiceException exception) { isError = true; status = exception.Message; } } }Überlegen Sie, was dieser Code bewirkt.
- Darin
OnInitializedAsyncwird die Zeitzone des authentifizierten Benutzers abgerufen. - Initialisiert
CreateEventdarin ein neues Event-Objekt mithilfe der Werte aus dem Formular. - Es verwendet das Graph SDK, um das Ereignis dem Kalender des Benutzers hinzuzufügen.
- Darin
Speichern Sie alle Änderungen, und starten Sie die App neu. Wählen Sie auf der Kalenderseite das Ereignis "Neu" aus. Füllen Sie das Formular aus, und wählen Sie " Erstellen" aus.

Herzlichen Glückwunsch!
Sie haben das Lernprogramm für Die Webserverwebassembly von Microsoft Graph abgeschlossen. Nachdem Sie nun über eine funktionierende App verfügen, die Microsoft Graph aufruft, können Sie experimentieren und neue Features hinzufügen. Besuchen Sie die Übersicht über Microsoft Graph, um alle Daten anzuzeigen, auf die Sie mit Microsoft Graph zugreifen können.
Feedback
Bitte geben Sie Feedback zu diesem Lernprogramm im GitHub Repository.
Liegt ein Problem mit diesem Abschnitt vor? Wenn ja, senden Sie uns Feedback, damit wir den Abschnitt verbessern können.