Erstellen von ASP.net-Kern-MVC-apps mit Microsoft Graph
In diesem Lernprogramm erfahren Sie, wie Sie eine ASP.NET Core Web-App erstellen, die die Microsoft Graph-API verwendet, um Kalenderinformationen für einen Benutzer abzurufen.
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 Core 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 Office 365 Abonnement zu erhalten.
Hinweis
Dieses Lernprogramm wurde mit .NET Core SDK Version 5.0.102 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 ASP.net-Kern-MVC-Webanwendung
Erstellen Sie zunächst eine ASP.NET Core Web-App.
Ö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 mvc -o GraphTutorial
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 run
Öffnen Sie Ihren Browser, und navigieren Sie zu
https://localhost:5001
. Wenn alles funktioniert, sollte eine Standardseite ASP.NET Core angezeigt werden.
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.Identity.Web zum Anfordern und Verwalten von Zugriffstoken.
- Microsoft.Identity.Web.MicrosoftGraph zum Hinzufügen des Microsoft Graph SDK über die Abhängigkeitsinjektion.
- Microsoft.Identity.Web.UI für die Anmelde- und Abmeldebenutzeroberfläche.
- TimeZoneConverter für die plattformübergreifende Behandlung von zeitzonenübergreifenden Bezeichnern.
Führen Sie die folgenden Befehle in Der CLI aus, um die Abhängigkeiten zu installieren.
dotnet add package Microsoft.Identity.Web --version 1.5.1 dotnet add package Microsoft.Identity.Web.MicrosoftGraph --version 1.5.1 dotnet add package Microsoft.Identity.Web.UI --version 1.5.1 dotnet add package TimeZoneConverter
Entwerfen der App
In diesem Abschnitt erstellen Sie die grundlegende UI-Struktur der Anwendung.
Implementieren von Methoden zur Warnungserweiterung
In diesem Abschnitt erstellen Sie Erweiterungsmethoden für den Typ, der IActionResult
von Controlleransichten zurückgegeben wird. Diese Erweiterung ermöglicht das Übergeben temporärer Fehler- oder Erfolgsmeldungen an die Ansicht.
Tipp
Sie können einen beliebigen Text-Editor verwenden, um die Quelldateien für dieses Lernprogramm zu bearbeiten. Visual Studio Code bietet jedoch zusätzliche Features, z. B. Debugging und IntelliSense.
Erstellen Sie ein neues Verzeichnis im GraphTutorial-Verzeichnis mit dem Namen "Alerts".
Erstellen Sie eine neue Datei mit dem Namen WithAlertResult.cs im Verzeichnis ./Alerts , und fügen Sie den folgenden Code hinzu.
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.Extensions.DependencyInjection; using System.Threading.Tasks; namespace GraphTutorial { // WithAlertResult adds temporary error/info/success // messages to the result of a controller action. // This data is read and displayed by the _AlertPartial view public class WithAlertResult : IActionResult { public IActionResult Result { get; } public string Type { get; } public string Message { get; } public string DebugInfo { get; } public WithAlertResult(IActionResult result, string type, string message, string debugInfo) { Result = result; Type = type; Message = message; DebugInfo = debugInfo; } public async Task ExecuteResultAsync(ActionContext context) { var factory = context.HttpContext.RequestServices .GetService<ITempDataDictionaryFactory>(); var tempData = factory.GetTempData(context.HttpContext); tempData["_alertType"] = Type; tempData["_alertMessage"] = Message; tempData["_alertDebugInfo"] = DebugInfo; await Result.ExecuteResultAsync(context); } } }
Erstellen Sie eine neue Datei mit dem Namen AlertExtensions.cs im Verzeichnis ./Alerts , und fügen Sie den folgenden Code hinzu.
using Microsoft.AspNetCore.Mvc; namespace GraphTutorial { public static class AlertExtensions { public static IActionResult WithError(this IActionResult result, string message, string debugInfo = null) { return Alert(result, "danger", message, debugInfo); } public static IActionResult WithSuccess(this IActionResult result, string message, string debugInfo = null) { return Alert(result, "success", message, debugInfo); } public static IActionResult WithInfo(this IActionResult result, string message, string debugInfo = null) { return Alert(result, "info", message, debugInfo); } private static IActionResult Alert(IActionResult result, string type, string message, string debugInfo) { return new WithAlertResult(result, type, message, debugInfo); } } }
Implementieren von Methoden zur Benutzerdatenerweiterung
In diesem Abschnitt erstellen Sie Erweiterungsmethoden für das ClaimsPrincipal
von der Microsoft Identity-Plattform generierte Objekt. Auf diese Weise können Sie die vorhandene Benutzeridentität mit Daten von Microsoft Graph erweitern.
Hinweis
Dieser Code ist vorerst nur ein Platzhalter, den Sie in einem späteren Abschnitt abschließen.
Erstellen Sie ein neues Verzeichnis im GraphTutorial-Verzeichnis mit dem Namen Graph.
Erstellen Sie eine neue Datei mit dem Namen GraphClaimsPrincipalExtensions.cs , und fügen Sie den folgenden Code hinzu.
using System.Security.Claims; namespace GraphTutorial { public static class GraphClaimTypes { public const string DisplayName ="graph_name"; public const string Email = "graph_email"; public const string Photo = "graph_photo"; public const string TimeZone = "graph_timezone"; public const string DateTimeFormat = "graph_datetimeformat"; } // Helper methods to access Graph user data stored in // the claims principal public static class GraphClaimsPrincipalExtensions { public static string GetUserGraphDisplayName(this ClaimsPrincipal claimsPrincipal) { return "Adele Vance"; } public static string GetUserGraphEmail(this ClaimsPrincipal claimsPrincipal) { return "adelev@contoso.com"; } public static string GetUserGraphPhoto(this ClaimsPrincipal claimsPrincipal) { return "/img/no-profile-photo.png"; } } }
Erstellen von Ansichten
In diesem Abschnitt implementieren Sie die Razor-Ansichten für die Anwendung.
Fügen Sie eine neue Datei mit dem Namen _LoginPartial.cshtml im Verzeichnis ./Views/Shared hinzu, und fügen Sie den folgenden Code hinzu.
@using GraphTutorial <ul class="nav navbar-nav"> @if (User.Identity.IsAuthenticated) { <li class="nav-item dropdown"> <a class="nav-link dropdown-toggle" data-toggle="dropdown" href="#" role="button"> <img src="@User.GetUserGraphPhoto()" 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">@User.GetUserGraphDisplayName()</h5> <p class="dropdown-item-text text-muted mb-0">@User.GetUserGraphEmail()</p> <div class="dropdown-divider"></div> <a class="dropdown-item" asp-area="MicrosoftIdentity" asp-controller="Account" asp-action="SignOut">Sign out</a> </div> </li> } else { <li class="nav-item"> <a class="nav-link" asp-area="MicrosoftIdentity" asp-controller="Account" asp-action="SignIn">Sign in</a> </li> } </ul>
Fügen Sie eine neue Datei mit dem Namen _AlertPartial.cshtml im Verzeichnis ./Views/Shared hinzu, und fügen Sie den folgenden Code hinzu.
@{ var type = $"{TempData["_alertType"]}"; var message = $"{TempData["_alertMessage"]}"; var debugInfo = $"{TempData["_alertDebugInfo"]}"; } @if (!string.IsNullOrEmpty(type)) { <div class="alert alert-@type" role="alert"> @if (string.IsNullOrEmpty(debugInfo)) { <p class="mb-0">@message</p> } else { <p class="mb-3">@message</p> <pre class="alert-pre border bg-light p-2"><code>@debugInfo</code></pre> } </div> }
Öffnen Sie die Datei ./Views/Shared/_Layout. cshtml, und ersetzen Sie den gesamten Inhalt durch den folgenden Code, um das globale Layout der App zu aktualisieren.
@{ string controller = $"{ViewContext.RouteData.Values["controller"]}"; } <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>@ViewData["Title"] - GraphTutorial</title> <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" /> <link rel="stylesheet" href="~/css/site.css" /> </head> <body> <header> <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-dark bg-dark border-bottom box-shadow mb-3"> <div class="container"> <a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">GraphTutorial</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="navbar-collapse collapse mr-auto"> <ul class="navbar-nav flex-grow-1"> <li class="@(controller == "Home" ? "nav-item active" : "nav-item")"> <a class="nav-link" asp-area="" asp-controller="Home" asp-action="Index">Home</a> </li> @if (User.Identity.IsAuthenticated) { <li class="@(controller == "Calendar" ? "nav-item active" : "nav-item")"> <a class="nav-link" asp-area="" asp-controller="Calendar" asp-action="Index">Calendar</a> </li> } </ul> <partial name="_LoginPartial"/> </div> </div> </nav> </header> <div class="container"> <main role="main" class="pb-3"> <partial name="_AlertPartial"/> @RenderBody() </main> </div> <footer class="border-top footer text-muted"> <div class="container"> © 2020 - GraphTutorial - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a> </div> </footer> <script src="~/lib/jquery/dist/jquery.min.js"></script> <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script> <script src="~/js/site.js" asp-append-version="true"></script> @RenderSection("Scripts", required: false) </body> </html>
Öffnen Sie ./wwwroot/css/site.css , und fügen Sie den folgenden Code am Ende der Datei hinzu.
.nav-profile-photo { width: 32px; } .alert-pre { word-wrap: break-word; word-break: break-all; white-space: pre-wrap; } .calendar-view-date-cell { width: 150px; } .calendar-view-date { width: 40px; font-size: 36px; line-height: 36px; margin-right: 10px; } .calendar-view-month { font-size: 0.75em; } .calendar-view-timespan { width: 200px; } .calendar-view-subject { font-size: 1.25em; } .calendar-view-organizer { font-size: .75em; } .calendar-view-date-diff { font-size: .75em }
Öffnen Sie die Datei ./Views/Home/index.cshtml , und ersetzen Sie den Inhalt durch Folgendes.
@{ ViewData["Title"] = "Home Page"; } @using GraphTutorial <div class="jumbotron"> <h1>ASP.NET Core Graph Tutorial</h1> <p class="lead">This sample app shows how to use the Microsoft Graph API to access a user's data from ASP.NET Core</p> @if (User.Identity.IsAuthenticated) { <h4>Welcome @User.GetUserGraphDisplayName()!</h4> <p>Use the navigation bar at the top of the page to get started.</p> } else { <a class="btn btn-primary btn-large" asp-area="MicrosoftIdentity" asp-controller="Account" asp-action="SignIn">Click here to sign in</a> } </div>
Erstellen Sie ein neues Verzeichnis im Verzeichnis "./wwwroot " mit dem Namen "img". Fügen Sie eine Bilddatei ihrer Wahl namens no-profile-photo.png in diesem Verzeichnis 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 starten Sie den Server neu (
dotnet run
). Jetzt sollte die App ganz anders aussehen.
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
ASP.NET Core Graph Tutorial
fest. - Legen Sie Unterstützte Kontotypen auf Konten in allen Organisationsverzeichnissen und persönliche Microsoft-Konten fest.
- Legen Sie unter Umleitungs-URI die erste Dropdownoption auf
Web
fest, und legen Sie den Wert aufhttps://localhost:5001/
fest.
- Legen Sie Name auf
Wählen Sie Registrieren aus. Kopieren Sie auf der Seite ASP.NET Core Graph Lernprogramm den Wert der Anwendungs-ID (Client-ID), und speichern Sie sie, sie benötigen Sie im nächsten Schritt.
Wählen Sie unter Verwalten die Option Authentifizierung aus. Fügen Sie unter "Umleitungs-URIs " einen URI mit dem Wert
https://localhost:5001/signin-oidc
hinzu.Legen Sie die Abmelde-URL auf
https://localhost:5001/signout-oidc
.Suchen Sie den Abschnitt Implizite Gewährung, und aktivieren Sie ID-Token. Klicken Sie auf Speichern.
Wählen Sie unter Verwalten die Option Zertifikate und Geheime Clientschlüssel aus. Wählen Sie die Schaltfläche Neuen geheimen Clientschlüssel aus. Geben Sie einen Wert in Beschreibung ein, wählen Sie eine der Optionen für Gilt bis aus, und wählen Sie dann Hinzufügen aus.
Kopieren Sie den Wert des geheimen Clientschlüssels, bevor Sie diese Seite verlassen. Sie benötigen ihn im nächsten Schritt.
Wichtig
Dieser geheime Clientschlüssel wird nicht noch einmal angezeigt, stellen Sie daher sicher, dass Sie ihn jetzt kopieren.
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. In diesem Schritt konfigurieren Sie die Microsoft.Identity.Web-Bibliothek .
Wichtig
Um das Speichern der Anwendungs-ID und des geheimen Schlüssels in der Quelle zu vermeiden, verwenden Sie den .NET Secret Manager , um diese Werte zu speichern. Der Geheime Manager dient nur zu Entwicklungszwecken, Produktions-Apps sollten einen vertrauenswürdigen geheimen Manager zum Speichern geheimer Schlüssel verwenden.
Öffnen Sie ./appsettings.json , und ersetzen Sie den Inhalt durch Folgendes.
{ "AzureAd": { "Instance": "https://login.microsoftonline.com/", "TenantId": "common", "CallbackPath": "/signin-oidc" }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "AllowedHosts": "*" }
Öffnen Sie Ihre CLI in dem Verzeichnis, in dem sich GraphTutorial.csproj befindet, und führen Sie die folgenden Befehle aus, und ersetzen Sie dabei Ihre Anwendungs-ID aus dem Azure-Portal und
YOUR_APP_SECRET
ihren geheimenYOUR_APP_ID
Anwendungsschlüssel.dotnet user-secrets init dotnet user-secrets set "AzureAd:ClientId" "YOUR_APP_ID" dotnet user-secrets set "AzureAd:ClientSecret" "YOUR_APP_SECRET"
Implementieren der Anmeldung
Fügen Sie zunächst die Microsoft Identity Platform-Dienste zur Anwendung hinzu.
Erstellen Sie eine neue Datei mit dem Namen "GraphConstants.cs" im Verzeichnis "./Graph", und fügen Sie den folgenden Code hinzu.
namespace GraphTutorial { public static class GraphConstants { // Defines the permission scopes used by the app public readonly static string[] Scopes = { "User.Read", "MailboxSettings.Read", "Calendars.ReadWrite" }; } }
Öffnen Sie die Datei ./Startup.cs , und fügen Sie die folgenden
using
Anweisungen am Anfang der Datei hinzu.using Microsoft.AspNetCore.Authentication.OpenIdConnect; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc.Authorization; using Microsoft.Identity.Web; using Microsoft.Identity.Web.UI; using Microsoft.IdentityModel.Protocols.OpenIdConnect; using Microsoft.Graph; using System.Net; using System.Net.Http.Headers;
Ersetzen Sie die vorhandene
ConfigureServices
-Funktion durch Folgendes.public void ConfigureServices(IServiceCollection services) { services // Use OpenId authentication .AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) // Specify this is a web app and needs auth code flow .AddMicrosoftIdentityWebApp(Configuration) // Add ability to call web API (Graph) // and get access tokens .EnableTokenAcquisitionToCallDownstreamApi(options => { Configuration.Bind("AzureAd", options); }, GraphConstants.Scopes) // Use in-memory token cache // See https://github.com/AzureAD/microsoft-identity-web/wiki/token-cache-serialization .AddInMemoryTokenCaches(); // Require authentication services.AddControllersWithViews(options => { var policy = new AuthorizationPolicyBuilder() .RequireAuthenticatedUser() .Build(); options.Filters.Add(new AuthorizeFilter(policy)); }) // Add the Microsoft Identity UI pages for signin/out .AddMicrosoftIdentityUI(); }
Fügen Sie in der
Configure
Funktion die folgende Zeile über derapp.UseAuthorization();
Zeile hinzu.app.UseAuthentication();
Öffnen Sie ./Controllers/HomeController.cs , und ersetzen Sie den Inhalt durch Folgendes.
using GraphTutorial.Models; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Microsoft.Identity.Web; using System.Diagnostics; using System.Threading.Tasks; namespace GraphTutorial.Controllers { public class HomeController : Controller { ITokenAcquisition _tokenAcquisition; private readonly ILogger<HomeController> _logger; // Get the ITokenAcquisition interface via // dependency injection public HomeController( ITokenAcquisition tokenAcquisition, ILogger<HomeController> logger) { _tokenAcquisition = tokenAcquisition; _logger = logger; } public async Task<IActionResult> Index() { // TEMPORARY // Get the token and display it try { string token = await _tokenAcquisition .GetAccessTokenForUserAsync(GraphConstants.Scopes); return View().WithInfo("Token acquired", token); } catch (MicrosoftIdentityWebChallengeUserException) { return Challenge(); } } public IActionResult Privacy() { return View(); } [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] public IActionResult Error() { return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); } [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] [AllowAnonymous] public IActionResult ErrorWithMessage(string message, string debug) { return View("Index").WithError(message, debug); } } }
Speichern Sie Ihre Änderungen und starten Sie das Projekt. Melden Sie sich mit Ihrem Microsoft-Konto an.
Überprüfen Sie die Zustimmungsaufforderung. Die Liste der Berechtigungen entspricht der Liste der Berechtigungsbereiche, die in ./Graph/GraphConstants.cs konfiguriert sind.
- Verwalten des Zugriffs auf Daten, auf die Sie Zugriff erhalten haben: (
offline_access
) Diese Berechtigung wird von MSAL angefordert, um Aktualisierungstoken abzurufen. - Melden Sie sich an, und lesen Sie Ihr Profil: (
User.Read
) Mit dieser Berechtigung kann die App das Profil und das Profilfoto des angemeldeten Benutzers abrufen. - Lesen Der Postfacheinstellungen: (
MailboxSettings.Read
) Mit dieser Berechtigung kann die App die Postfacheinstellungen des Benutzers lesen, einschließlich Zeitzone und Zeitformat. - Vollzugriff auf Ihre Kalender: (
Calendars.ReadWrite
) Mit dieser Berechtigung kann die App Ereignisse im Kalender des Benutzers lesen, neue Ereignisse hinzufügen und vorhandene ändern.
Weitere Informationen zur Zustimmung finden Sie unter "Grundlegendes zu Azure AD Anwendungsgenehmigungserfahrungen".
- Verwalten des Zugriffs auf Daten, auf die Sie Zugriff erhalten haben: (
Stimmen Sie den angeforderten Berechtigungen zu. Der Browser leitet zur App um, in der Sie das Token sehen.
Benutzerdetails abrufen
Sobald sich der Benutzer angemeldet hat, können Sie dessen Informationen über Microsoft Graph abrufen.
Öffnen Sie ./Graph/GraphClaimsPrincipalExtensions.cs, und ersetzen Sie den gesamten Inhalt durch Folgendes.
using Microsoft.Graph; using System; using System.IO; using System.Security.Claims; namespace GraphTutorial { public static class GraphClaimTypes { public const string DisplayName ="graph_name"; 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 GetUserGraphDisplayName(this ClaimsPrincipal claimsPrincipal) { return claimsPrincipal.FindFirstValue(GraphClaimTypes.DisplayName); } public static string GetUserGraphEmail(this ClaimsPrincipal claimsPrincipal) { return claimsPrincipal.FindFirstValue(GraphClaimTypes.Email); } public static string GetUserGraphPhoto(this ClaimsPrincipal claimsPrincipal) { return claimsPrincipal.FindFirstValue(GraphClaimTypes.Photo); } public static string GetUserGraphTimeZone(this ClaimsPrincipal claimsPrincipal) { return claimsPrincipal.FindFirstValue(GraphClaimTypes.TimeZone); } public static string GetUserGraphTimeFormat(this ClaimsPrincipal claimsPrincipal) { return claimsPrincipal.FindFirstValue(GraphClaimTypes.TimeFormat); } public static void AddUserGraphInfo(this ClaimsPrincipal claimsPrincipal, User user) { var identity = claimsPrincipal.Identity as ClaimsIdentity; identity.AddClaim( new Claim(GraphClaimTypes.DisplayName, user.DisplayName)); 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)); } public static void AddUserGraphPhoto(this ClaimsPrincipal claimsPrincipal, Stream photoStream) { var identity = claimsPrincipal.Identity as ClaimsIdentity; if (photoStream == null) { // Add the default profile photo identity.AddClaim( new Claim(GraphClaimTypes.Photo, "/img/no-profile-photo.png")); return; } // 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 photoUrl = $"data:image/png;base64,{Convert.ToBase64String(photoBytes)}"; identity.AddClaim( new Claim(GraphClaimTypes.Photo, photoUrl)); } } }
Öffnen Sie "./Startup.cs", und ersetzen Sie die vorhandene
.AddMicrosoftIdentityWebApp(Configuration)
Zeile durch den folgenden Code.// Specify this is a web app and needs auth code flow .AddMicrosoftIdentityWebApp(options => { Configuration.Bind("AzureAd", options); options.Prompt = "select_account"; options.Events.OnTokenValidated = async context => { var tokenAcquisition = context.HttpContext.RequestServices .GetRequiredService<ITokenAcquisition>(); var graphClient = new GraphServiceClient( new DelegateAuthenticationProvider(async (request) => { var token = await tokenAcquisition .GetAccessTokenForUserAsync(GraphConstants.Scopes, user:context.Principal); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token); }) ); // Get user information from Graph var user = await graphClient.Me.Request() .Select(u => new { u.DisplayName, u.Mail, u.UserPrincipalName, u.MailboxSettings }) .GetAsync(); context.Principal.AddUserGraphInfo(user); // Get the user's photo // If the user doesn't have a photo, this throws try { var photo = await graphClient.Me .Photos["48x48"] .Content .Request() .GetAsync(); context.Principal.AddUserGraphPhoto(photo); } catch (ServiceException ex) { if (ex.IsMatch("ErrorItemNotFound") || ex.IsMatch("ConsumerPhotoIsNotSupported")) { context.Principal.AddUserGraphPhoto(null); } else { throw; } } }; options.Events.OnAuthenticationFailed = context => { var error = WebUtility.UrlEncode(context.Exception.Message); context.Response .Redirect($"/Home/ErrorWithMessage?message=Authentication+error&debug={error}"); context.HandleResponse(); return Task.FromResult(0); }; options.Events.OnRemoteFailure = context => { if (context.Failure is OpenIdConnectProtocolException) { var error = WebUtility.UrlEncode(context.Failure.Message); context.Response .Redirect($"/Home/ErrorWithMessage?message=Sign+in+error&debug={error}"); context.HandleResponse(); } return Task.FromResult(0); }; })
Überlegen Sie, was dieser Code bewirkt.
- Es wird ein Ereignishandler für das
OnTokenValidated
Ereignis hinzugefügt.- Es verwendet die
ITokenAcquisition
Schnittstelle, um ein Zugriffstoken abzurufen. - Sie ruft Microsoft Graph auf, um das Profil und Foto des Benutzers abzurufen.
- Die Graph Informationen werden der Identität des Benutzers hinzugefügt.
- Es verwendet die
- Es wird ein Ereignishandler für das
Fügen Sie den folgenden Funktionsaufruf nach dem
EnableTokenAcquisitionToCallDownstreamApi
Aufruf und vor demAddInMemoryTokenCaches
Aufruf hinzu.// Add a GraphServiceClient via dependency injection .AddMicrosoftGraph(options => { options.Scopes = string.Join(' ', GraphConstants.Scopes); })
Dadurch wird ein authentifizierter GraphServiceClient für Controller über die Abhängigkeitsinjektion zur Verfügung gestellt.
Öffnen Sie ./Controllers/HomeController.cs , und ersetzen Sie die
Index
Funktion durch Folgendes.public IActionResult Index() { return View(); }
Entfernen Sie alle Verweise auf
ITokenAcquisition
die HomeController-Klasse .Speichern Sie Ihre Änderungen, starten Sie die App, und durchlaufen Sie den Anmeldevorgang. Sie sollten wieder auf der Startseite angezeigt werden, aber die Benutzeroberfläche sollte geändert werden, um anzugeben, dass Sie angemeldet sind.
Klicken Sie auf den Benutzer-Avatar in der oberen rechten Ecke, um auf den Abmeldelink zuzugreifen. Wenn Sie auf Abmelden klicken, wird die Sitzung zurückgesetzt und Sie kehren zur Startseite zurück.
Tipp
Wenn Ihr Benutzername auf der Startseite nicht angezeigt wird und die Dropdownliste "Avatar verwenden" keinen Namen und keine E-Mail enthält, nachdem Sie diese Änderungen vorgenommen haben, melden Sie sich ab und melden Sie sich wieder an.
Speichern und Aktualisieren von Token
An diesem Punkt verfügt Ihre Anwendung über ein Zugriffstoken, das in der Authorization
Kopfzeile von API-Aufrufen gesendet wird. Dies ist das Token, durch das die App im Namen des Benutzers auf Microsoft Graph zugreifen kann.
Dieses Token ist jedoch nur kurzzeitig verfügbar. Das Token läuft eine Stunde nach der Ausstellung ab. An dieser Stelle kommt das Aktualisierungstoken ins Spiel. Anhand des Aktualisierungstoken ist die App in der Lage, ein neues Zugriffstoken anzufordern, ohne dass der Benutzer sich erneut anmelden muss.
Da die App die Microsoft.Identity.Web-Bibliothek verwendet, müssen Sie keine Tokenspeicher- oder Aktualisierungslogik implementieren.
Die App verwendet den Speichertokencache, der für Apps ausreicht, die beim Neustart der App keine Token beibehalten müssen. Produktions-Apps verwenden stattdessen möglicherweise die Optionen für verteilten Cache in der Microsoft.Identity.Web-Bibliothek.
Die GetAccessTokenForUserAsync
Methode behandelt den Ablauf und die Aktualisierung des Tokens für Sie. Es überprüft zuerst das zwischengespeicherte Token und gibt es zurück, wenn es nicht abgelaufen ist. Wenn es abgelaufen ist, wird das zwischengespeicherte Aktualisierungstoken verwendet, um ein neues abzurufen.
Der GraphServiceClient , den Controller über die Abhängigkeitsinjektion erhalten, wird mit einem Authentifizierungsanbieter vorkonfiguriert, der für Sie verwendet GetAccessTokenForUserAsync
wird.
Abrufen einer Kalenderansicht
In diesem Abschnitt integrieren Sie Microsoft Graph in die Anwendung. Für diese Anwendung verwenden Sie die Microsoft Graph-Clientbibliothek für .NET, um Aufrufe an Microsoft Graph zu tätigen.
Abrufen von Kalenderereignissen von Outlook
Erstellen Sie zunächst einen neuen Controller für Kalenderansichten.
Fügen Sie eine neue Datei namens "CalendarController.cs " im Verzeichnis "./Controllers" hinzu, und fügen Sie den folgenden Code hinzu.
using GraphTutorial.Models; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Microsoft.Identity.Web; using Microsoft.Graph; using System; using System.Collections.Generic; using System.Threading.Tasks; using TimeZoneConverter; namespace GraphTutorial.Controllers { public class CalendarController : Controller { private readonly GraphServiceClient _graphClient; private readonly ILogger<HomeController> _logger; public CalendarController( GraphServiceClient graphClient, ILogger<HomeController> logger) { _graphClient = graphClient; _logger = logger; } } }
Fügen Sie der Klasse die
CalendarController
folgenden Funktionen hinzu, um die Kalenderansicht des Benutzers abzurufen.private async Task<IList<Event>> GetUserWeekCalendar(DateTime startOfWeekUtc) { // Configure a calendar view for the current week var endOfWeekUtc = startOfWeekUtc.AddDays(7); var viewOptions = new List<QueryOption> { new QueryOption("startDateTime", startOfWeekUtc.ToString("o")), new QueryOption("endDateTime", endOfWeekUtc.ToString("o")) }; var events = 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=\"{User.GetUserGraphTimeZone()}\"") // 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(); IList<Event> allEvents; // Handle case where there are more than 50 if (events.NextPageRequest != null) { allEvents = new List<Event>(); // Create a page iterator to iterate over subsequent pages // of results. Build a list from the results var pageIterator = PageIterator<Event>.CreatePageIterator( _graphClient, events, (e) => { allEvents.Add(e); return true; } ); await pageIterator.IterateAsync(); } else { // If only one page, just use the result allEvents = events.CurrentPage; } return allEvents; } private static DateTime GetUtcStartOfWeekInTimeZone(DateTime today, TimeZoneInfo timeZone) { // 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, timeZone); }
Überlegen Sie, was der Code
GetUserWeekCalendar
bewirkt.- Es verwendet die Zeitzone des Benutzers, um UTC-Start- und Enddatums-/-uhrzeitwerte für die Woche abzurufen.
- Es fragt die Kalenderansicht des Benutzers ab, um alle Ereignisse abzurufen, die zwischen dem Start- und Enddatum/der Endzeit liegen. Wenn Sie eine Kalenderansicht verwenden, anstatt Ereignisse aufzulisten , werden wiederkehrende Ereignisse erweitert und alle Vorkommen zurückgegeben, die im angegebenen Zeitfenster auftreten.
- Der Header wird verwendet
Prefer: outlook.timezone
, um Ergebnisse in der Zeitzone des Benutzers abzurufen. - Es wird verwendet
Select
, um die Felder einzuschränken, die nur auf die von der App verwendeten zurückkommen. - Es wird
OrderBy
verwendet, um die Ergebnisse chronologisch zu sortieren. - Es wird eine
PageIterator
Seite in der Ereignissammlung verwendet. Dies behandelt den Fall, dass der Benutzer mehr Ereignisse im Kalender hat als die angeforderte Seitengröße.
Fügen Sie der Klasse die
CalendarController
folgende Funktion hinzu, um eine temporäre Ansicht der zurückgegebenen Daten zu implementieren.// Minimum permission scope needed for this view [AuthorizeForScopes(Scopes = new[] { "Calendars.Read" })] public async Task<IActionResult> Index() { try { var userTimeZone = TZConvert.GetTimeZoneInfo( User.GetUserGraphTimeZone()); var startOfWeek = CalendarController.GetUtcStartOfWeekInTimeZone( DateTime.Today, userTimeZone); var events = await GetUserWeekCalendar(startOfWeek); // Return a JSON dump of events return new ContentResult { Content = _graphClient.HttpProvider.Serializer.SerializeObject(events), ContentType = "application/json" }; } catch (ServiceException ex) { if (ex.InnerException is MicrosoftIdentityWebChallengeUserException) { throw; } return new ContentResult { Content = $"Error getting calendar view: {ex.Message}", ContentType = "text/plain" }; } }
Starten Sie die App, melden Sie sich an, und klicken Sie auf den Link Kalender in der Navigationsleiste. Wenn alles funktioniert, sollte ein JSON-Abbild von Ereignissen im Kalender des Benutzers angezeigt werden.
Anzeigen der Ergebnisse
Jetzt können Sie eine Ansicht hinzufügen, um die Ergebnisse benutzerfreundlicher anzuzeigen.
Erstellen von Ansichtsmodellen
Erstellen Sie eine neue Datei mit dem Namen CalendarViewEvent.cs im Verzeichnis ./Models , und fügen Sie den folgenden Code hinzu.
using Microsoft.Graph; using System; namespace GraphTutorial.Models { public class CalendarViewEvent { public string Subject { get; private set; } public string Organizer { get; private set; } public DateTime Start { get; private set; } public DateTime End { get; private set; } public CalendarViewEvent(Event graphEvent) { Subject = graphEvent.Subject; Organizer = graphEvent.Organizer.EmailAddress.Name; Start = DateTime.Parse(graphEvent.Start.DateTime); End = DateTime.Parse(graphEvent.End.DateTime); } } }
Erstellen Sie eine neue Datei namens DailyViewModel.cs im Verzeichnis ./Models , und fügen Sie den folgenden Code hinzu.
using System; using System.Collections.Generic; namespace GraphTutorial.Models { public class DailyViewModel { // Day the view is for public DateTime Day { get; private set; } // Events on this day public IEnumerable<CalendarViewEvent> Events { get; private set; } public DailyViewModel(DateTime day, IEnumerable<CalendarViewEvent> events) { Day = day; Events = events; } } }
Erstellen Sie eine neue Datei mit dem Namen CalendarViewModel.cs im Verzeichnis ./Models , und fügen Sie den folgenden Code hinzu.
using Microsoft.Graph; using System; using System.Collections.Generic; using System.Linq; namespace GraphTutorial.Models { public class CalendarViewModel { private DateTime _startOfWeek; private DateTime _endOfWeek; private List<CalendarViewEvent> _events; public CalendarViewModel() { _startOfWeek = DateTime.MinValue; _events = new List<CalendarViewEvent>(); } public CalendarViewModel(DateTime startOfWeek, IEnumerable<Event> events) { _startOfWeek = startOfWeek; _endOfWeek = startOfWeek.AddDays(7); _events = new List<CalendarViewEvent>(); if (events != null) { foreach (var item in events) { _events.Add(new CalendarViewEvent(item)); } } } // Get the start - end dates of the week public string TimeSpan() { return $"{_startOfWeek.ToString("MMMM d, yyyy")} - {_startOfWeek.AddDays(6).ToString("MMMM d, yyyy")}"; } // Property accessors to pass to the daily view partial // These properties get all events on the specific day public DailyViewModel Sunday { get { return new DailyViewModel( _startOfWeek, GetEventsForDay(System.DayOfWeek.Sunday)); } } public DailyViewModel Monday { get { return new DailyViewModel( _startOfWeek.AddDays(1), GetEventsForDay(System.DayOfWeek.Monday)); } } public DailyViewModel Tuesday { get { return new DailyViewModel( _startOfWeek.AddDays(2), GetEventsForDay(System.DayOfWeek.Tuesday)); } } public DailyViewModel Wednesday { get { return new DailyViewModel( _startOfWeek.AddDays(3), GetEventsForDay(System.DayOfWeek.Wednesday)); } } public DailyViewModel Thursday { get { return new DailyViewModel( _startOfWeek.AddDays(4), GetEventsForDay(System.DayOfWeek.Thursday)); } } public DailyViewModel Friday { get { return new DailyViewModel( _startOfWeek.AddDays(5), GetEventsForDay(System.DayOfWeek.Friday)); } } public DailyViewModel Saturday { get { return new DailyViewModel( _startOfWeek.AddDays(6), GetEventsForDay(System.DayOfWeek.Saturday)); } } private IEnumerable<CalendarViewEvent> GetEventsForDay(System.DayOfWeek day) { return _events.Where(e => (e.End > _startOfWeek && ((e.Start.DayOfWeek.Equals(day) && e.Start >= _startOfWeek) || (e.End.DayOfWeek.Equals(day) && e.End < _endOfWeek)))); } } }
Erstellen von Ansichten
Erstellen Sie ein neues Verzeichnis namens "Calendar " im Verzeichnis "./Views ".
Erstellen Sie eine neue Datei mit dem Namen _DailyEventsPartial.cshtml im Verzeichnis ./Views/Calendar , und fügen Sie den folgenden Code hinzu.
@model DailyViewModel @{ bool dateCellAdded = false; var timeFormat = User.GetUserGraphTimeFormat(); var rowClass = Model.Day.Date.Equals(DateTime.Today.Date) ? "table-warning" : ""; } @if (Model.Events.Count() <= 0) { // Render an empty row for the day <tr> <td class="calendar-view-date-cell"> <div class="calendar-view-date float-left text-right">@Model.Day.Day</div> <div class="calendar-view-day">@Model.Day.ToString("dddd")</div> <div class="calendar-view-month text-muted">@Model.Day.ToString("MMMM, yyyy")</div> </td> <td></td> <td></td> </tr> } @foreach(var item in Model.Events) { <tr class="@rowClass"> @if (!dateCellAdded) { // Only add the day cell once dateCellAdded = true; <td class="calendar-view-date-cell" rowspan="@Model.Events.Count()"> <div class="calendar-view-date float-left text-right">@Model.Day.Day</div> <div class="calendar-view-day">@Model.Day.ToString("dddd")</div> <div class="calendar-view-month text-muted">@Model.Day.ToString("MMMM, yyyy")</div> </td> } <td class="calendar-view-timespan"> <div>@item.Start.ToString(timeFormat) - @item.End.ToString(timeFormat)</div> @if (item.Start.Date != Model.Day.Date) { <div class="calendar-view-date-diff">Start date: @item.Start.Date.ToShortDateString()</div> } @if (item.End.Date != Model.Day.Date) { <div class="calendar-view-date-diff">End date: @item.End.Date.ToShortDateString()</div> } </td> <td> <div class="calendar-view-subject">@item.Subject</div> <div class="calendar-view-organizer">@item.Organizer</div> </td> </tr> }
Erstellen Sie eine neue Datei mit dem Namen Index.cshtml im Verzeichnis ./Views/Calendar , und fügen Sie den folgenden Code hinzu.
@model CalendarViewModel @{ ViewData["Title"] = "Calendar"; } <div class="mb-3"> <h1 class="mb-3">@Model.TimeSpan()</h1> <a class="btn btn-light btn-sm" asp-controller="Calendar" asp-action="New">New event</a> </div> <div class="calendar-week"> <div class="table-responsive"> <table class="table table-sm"> <thead> <tr> <th>Date</th> <th>Time</th> <th>Event</th> </tr> </thead> <tbody> <partial name="_DailyEventsPartial" for="Sunday" /> <partial name="_DailyEventsPartial" for="Monday" /> <partial name="_DailyEventsPartial" for="Tuesday" /> <partial name="_DailyEventsPartial" for="Wednesday" /> <partial name="_DailyEventsPartial" for="Thursday" /> <partial name="_DailyEventsPartial" for="Friday" /> <partial name="_DailyEventsPartial" for="Saturday" /> </tbody> </table> </div> </div>
Kalendercontroller aktualisieren
Öffnen Sie ./Controllers/CalendarController.cs , und ersetzen Sie die vorhandene
Index
Funktion durch Folgendes.// Minimum permission scope needed for this view [AuthorizeForScopes(Scopes = new[] { "Calendars.Read" })] public async Task<IActionResult> Index() { try { var userTimeZone = TZConvert.GetTimeZoneInfo( User.GetUserGraphTimeZone()); var startOfWeekUtc = CalendarController.GetUtcStartOfWeekInTimeZone( DateTime.Today, userTimeZone); var events = await GetUserWeekCalendar(startOfWeekUtc); // Convert UTC start of week to user's time zone for // proper display var startOfWeekInTz = TimeZoneInfo.ConvertTimeFromUtc(startOfWeekUtc, userTimeZone); var model = new CalendarViewModel(startOfWeekInTz, events); return View(model); } catch (ServiceException ex) { if (ex.InnerException is MicrosoftIdentityWebChallengeUserException) { throw; } return View(new CalendarViewModel()) .WithError("Error getting calendar view", ex.Message); } }
Starten Sie die App, melden Sie sich an, und klicken Sie auf den Link Kalender. Die App sollte nun eine Tabelle mit Ereignissen rendern.
Erstellen eines neuen Ereignisses
In diesem Abschnitt fügen Sie die Möglichkeit hinzu, Ereignisse im Kalender des Benutzers zu erstellen.
Modell erstellen
Erstellen Sie eine neue Datei namens "NewEvent.cs " im Verzeichnis "./Models", und fügen Sie den folgenden Code hinzu.
using System; using System.ComponentModel.DataAnnotations; namespace GraphTutorial.Models { public class NewEvent { [Required] public string Subject { get; set; } public DateTime Start { get; set; } public DateTime End { get; set; } [DataType(DataType.MultilineText)] public string Body { get; set; } [RegularExpression(@"((\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*)*([;])*)*", ErrorMessage="Please enter one or more email addresses separated by a semi-colon (;)")] public string Attendees { get; set; } } }
Ansicht erstellen
Erstellen Sie eine neue Datei namens "New.cshtml " im Verzeichnis "./Views/Calendar ", und fügen Sie den folgenden Code hinzu.
@model NewEvent @{ ViewData["Title"] = "New event"; } <form asp-action="New"> <div asp-validation-summary="ModelOnly" class="text-danger"></div> <div class="form-group"> <label asp-for="Subject" class="control-label"></label> <input asp-for="Subject" class="form-control" /> <span asp-validation-for="Subject" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="Attendees" class="control-label"></label> <input asp-for="Attendees" class="form-control" /> <span asp-validation-for="Attendees" class="text-danger"></span> </div> <div class="form-row"> <div class="col"> <div class="form-group"> <label asp-for="Start" class="control-label"></label> <input asp-for="Start" class="form-control" /> <span asp-validation-for="Start" class="text-danger"></span> </div> </div> <div class="col"> <div class="form-group"> <label asp-for="End" class="control-label"></label> <input asp-for="End" class="form-control" /> <span asp-validation-for="End" class="text-danger"></span> </div> </div> </div> <div class="form-group"> <label asp-for="Body" class="control-label"></label> <textarea asp-for="Body" class="form-control"></textarea> <span asp-validation-for="Body" class="text-danger"></span> </div> <div class="form-group"> <input type="submit" value="Save" class="btn btn-primary" /> </div> </form> @section Scripts { @{await Html.RenderPartialAsync("_ValidationScriptsPartial");} }
Hinzufügen von Controlleraktionen
Öffnen Sie ./Controllers/CalendarController.cs , und fügen Sie der Klasse die
CalendarController
folgende Aktion hinzu, um das neue Ereignisformular zu rendern.// Minimum permission scope needed for this view [AuthorizeForScopes(Scopes = new[] { "Calendars.ReadWrite" })] public IActionResult New() { return View(); }
Fügen Sie der Klasse die
CalendarController
folgende Aktion hinzu, um das neue Ereignis aus dem Formular zu empfangen, wenn der Benutzer auf "Speichern" klickt, und verwenden Sie Microsoft Graph, um das Ereignis dem Kalender des Benutzers hinzuzufügen.[HttpPost] [ValidateAntiForgeryToken] [AuthorizeForScopes(Scopes = new[] { "Calendars.ReadWrite" })] public async Task<IActionResult> New([Bind("Subject,Attendees,Start,End,Body")] NewEvent newEvent) { var timeZone = User.GetUserGraphTimeZone(); // Create a Graph event with the required fields var graphEvent = new Event { Subject = newEvent.Subject, Start = new DateTimeTimeZone { DateTime = newEvent.Start.ToString("o"), // Use the user's time zone TimeZone = timeZone }, End = new DateTimeTimeZone { DateTime = newEvent.End.ToString("o"), // Use the user's time zone TimeZone = timeZone } }; // Add body if present if (!string.IsNullOrEmpty(newEvent.Body)) { graphEvent.Body = new ItemBody { ContentType = BodyType.Text, Content = newEvent.Body }; } // Add attendees if present if (!string.IsNullOrEmpty(newEvent.Attendees)) { var attendees = newEvent.Attendees.Split(';', StringSplitOptions.RemoveEmptyEntries); if (attendees.Length > 0) { var attendeeList = new List<Attendee>(); foreach (var attendee in attendees) { attendeeList.Add(new Attendee{ EmailAddress = new EmailAddress { Address = attendee }, Type = AttendeeType.Required }); } graphEvent.Attendees = attendeeList; } } try { // Add the event await _graphClient.Me.Events .Request() .AddAsync(graphEvent); // Redirect to the calendar view with a success message return RedirectToAction("Index").WithSuccess("Event created"); } catch (ServiceException ex) { // Redirect to the calendar view with an error message return RedirectToAction("Index") .WithError("Error creating event", ex.Error.Message); } }
Starten Sie die App, melden Sie sich an, und klicken Sie auf den Link Kalender. Klicken Sie auf die Schaltfläche "Neues Ereignis ", füllen Sie das Formular aus, und klicken Sie auf "Speichern".
Herzlichen Glückwunsch!
Sie haben das Lernprogramm ASP.NET Core 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.