Erstellen von Microsoft Teams-Apps mit Microsoft Graph
In diesem Lernprogramm erfahren Sie, wie Sie eine Microsoft Teams-App mit ASP.NET Core und der Microsoft Graph-API erstellen, 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 Folgendes auf Ihrem Entwicklungscomputer installiert haben.
Sie sollten auch über ein Microsoft-Geschäfts-, Schul- oder Unikonto in einem Microsoft 365 Mandanten verfügen, der benutzerdefiniertes Teams Querladen von Apps aktivierthat. Wenn Sie nicht über ein Microsoft-Geschäfts-, Schul- oder Unikonto verfügen oder Ihre Organisation benutzerdefiniertes Teams Querladen von Apps nicht aktiviert hat, können Sie sich für das Microsoft 365 Entwicklerprogramm registrieren, um ein kostenloses Office 365 Entwicklerabonnement 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 ASP.NET Core MVC-Web-App
Microsoft Teams Registerkartenanwendungen haben mehrere Optionen, um den Benutzer zu authentifizieren und Microsoft Graph aufzurufen. In dieser Übung implementieren Sie eine Registerkarte, die einmaliges Anmelden durchführt, um ein Authentifizierungstoken auf dem Client abzurufen, und verwenden dann den Im-Auftrag-von-Fluss auf dem Server, um dieses Token auszutauschen, um Zugriff auf Microsoft Graph zu erhalten.
Weitere Alternativen finden Sie in den folgenden Themen.
- Erstellen Sie eine Microsoft Teams Registerkarte mit dem Microsoft Graph Toolkit. Dieses Beispiel ist vollständig clientseitig und verwendet das Microsoft Graph Toolkit, um die Authentifizierung zu verarbeiten und Aufrufe an Microsoft Graph zu tätigen.
- Microsoft Teams Authentifizierungsbeispiel. Dieses Beispiel enthält mehrere Beispiele für verschiedene Authentifizierungsszenarien.
Erstellen des Projekts
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 webapp -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 Authentifizieren und Anfordern von Zugriffstoken.
- Microsoft.Identity.Web.MicrosoftGraph zum Hinzufügen von Microsoft Graph mit Microsoft.Identity.Web konfigurierter Support.
- Microsoft. Graph um die Version dieses Pakets zu aktualisieren, die von Microsoft.Identity.Web.MicrosoftGraph installiert wird.
- TimeZoneConverter zum Übersetzen Windows Zeitzonenbezeichner in IANA-Bezeichner.
Führen Sie die folgenden Befehle in Der CLI aus, um die Abhängigkeiten zu installieren.
dotnet add package Microsoft.Identity.Web --version 1.15.2 dotnet add package Microsoft.Identity.Web.MicrosoftGraph --version 1.15.2 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.
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.
Öffnen Sie ./Pages/Shared/_Layout.cshtml, und ersetzen Sie den gesamten Inhalt durch den folgenden Code, um das globale Layout der App zu aktualisieren.
<!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="https://static2.sharepointonline.com/files/fabric/office-ui-fabric-core/11.0.0/css/fabric.min.css" /> <link rel="stylesheet" href="~/css/site.css" /> </head> <body class="ms-Fabric"> <div class="container"> <main role="main"> @RenderBody() </main> </div> <script src="~/lib/jquery/dist/jquery.min.js"></script> <script src="https://statics.teams.cdn.office.net/sdk/v1.7.0/js/MicrosoftTeams.min.js"></script> <script src="~/js/site.js" asp-append-version="true"></script> @RenderSection("Scripts", required: false) </body> </html>
Dadurch wird Bootstrap durch Fluent Benutzeroberflächeersetzt, das Microsoft Teams SDKhinzugefügt und das Layout vereinfacht.
Öffnen Sie ./wwwroot/js/site.js, und fügen Sie den folgenden Code hinzu.
(function () { // Support Teams themes microsoftTeams.initialize(); // On load, match the current theme microsoftTeams.getContext((context) => { if(context.theme !== 'default') { // For Dark and High contrast, set text to white document.body.style.color = '#fff'; document.body.style.setProperty('--border-style', 'solid'); } }); // Register event listener for theme change microsoftTeams.registerOnThemeChangeHandler((theme)=> { if(theme !== 'default') { document.body.style.color = '#fff'; document.body.style.setProperty('--border-style', 'solid'); } else { // For default theme, remove inline style document.body.style.color = ''; document.body.style.setProperty('--border-style', 'none'); } }); })();
Dadurch wird ein einfacher Designänderungshandler hinzugefügt, um die Standardtextfarbe für dunkle Designs und Designs mit hohem Kontrast zu ändern.
Öffnen Sie ./wwwroot/css/site.css, und ersetzen Sie den Inhalt durch Folgendes.
:root { --border-style: none; } .tab-title { margin-bottom: .5em; } .event-card { margin: .5em; padding: 1em; border-style: var(--border-style); border-width: 1px; border-color: #fff; } .event-card div { margin-bottom: .25em; } .event-card .ms-Icon { margin-right: 10px; float: left; position: relative; top: 3px; } .event-card .ms-Icon--MapPin { top: 2px; } .form-container { max-width: 720px; } .form-label { display: block; margin-bottom: .25em; } .form-input { width: 100%; margin-bottom: .25em; padding: .5em; box-sizing: border-box; } .form-button { padding: .5em; } .result-panel { display: none; padding: 1em; margin: 1em; } .error-msg { color: red; } .success-msg { color: green; }
Öffnen Sie ./Pages/Index.cshtml, und ersetzen Sie den Inhalt durch den folgenden Code.
@page @model IndexModel @{ ViewData["Title"] = "Home page"; } <div id="tab-container"> <h1 class="ms-fontSize-24 ms-fontWeight-semibold">Loading...</h1> </div> @section Scripts { <script> </script> }
Öffnen Sie "./Startup.cs", und entfernen Sie die
app.UseHttpsRedirection();
Zeile in derConfigure
Methode. Dies ist erforderlich, damit der ngrok-Tunnel funktioniert.
Run ngrok
Microsoft Teams unterstützt kein lokales Hosting für Apps. Der Server, auf dem Ihre App gehostet wird, muss über HTTPS-Endpunkte in der Cloud verfügbar sein. Zum lokalen Debuggen können Sie ngrok verwenden, um eine öffentliche URL für Ihr lokal gehostetes Projekt zu erstellen.
Öffnen Sie Ihre CLI, und führen Sie den folgenden Befehl aus, um ngrok zu starten.
ngrok http 5000
Kopieren Sie nach dem Start von ngrok die HTTPS-Weiterleitungs-URL. Es sollte wie folgt
https://50153897dd4d.ngrok.io
aussehen: Sie benötigen diesen Wert in späteren Schritten.
Wichtig
Wenn Sie die kostenlose Version von ngrok verwenden, ändert sich die Weiterleitungs-URL jedes Mal, wenn Sie ngrok neu starten. Es wird empfohlen, ngrok so lange ausgeführt zu lassen, bis Sie dieses Lernprogramm abgeschlossen haben, um die gleiche URL beizubehalten. Wenn Sie ngrok neu starten müssen, müssen Sie Ihre URL überall dort aktualisieren, wo sie verwendet wird, und die App in Microsoft Teams neu installieren.
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, wobei
YOUR_NGROK_URL
sich die ngrok-Weiterleitungs-URL befindet, die Sie im vorherigen Abschnitt kopiert haben.- Legen Sie Name auf
Teams 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 aufYOUR_NGROK_URL/authcomplete
fest.
- Legen Sie Name auf
Wählen Sie Registrieren aus. Kopieren Sie auf der Seite Teams 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. Suchen Sie den Abschnitt "Implizite Genehmigung", und aktivieren Sie Zugriffstoken und ID-Token. Wählen Sie Speichern aus.
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.
Wählen Sie API-Berechtigungen unter "Verwalten" aus, und wählen Sie dann "Berechtigung hinzufügen" aus.
Wählen Sie Microsoft Graph und dann delegierte Berechtigungen aus.
Wählen Sie die folgenden Berechtigungen aus, und wählen Sie dann Berechtigungen hinzufügen aus.
- Calendars.ReadWrite – Dadurch kann die App den Kalender des Benutzers lesen und in diesen schreiben.
- MailboxSettings.Read – Dadurch kann die App die Zeitzone, das Datumsformat und das Zeitformat des Benutzers aus den Postfacheinstellungen abrufen.
Konfigurieren Teams einmaligen Anmeldens
In diesem Abschnitt aktualisieren Sie die App-Registrierung,um einmaliges Anmelden in Teams zu unterstützen.
Wählen Sie "API verfügbar machen" aus. Wählen Sie den Link "Festlegen" neben dem Anwendungs-ID-URI aus. Fügen Sie den Domänennamen der ngrok-Weiterleitungs-URL (mit einem schrägen Schrägstrich "/" an das Ende) zwischen den doppelten Schrägstrichen und der GUID ein. Die gesamte ID sollte etwa wie folgt aussehen:
api://50153897dd4d.ngrok.io/ae7d8088-3422-4c8c-a351-6ded0f21d615
.Wählen Sie im Abschnitt Bereiche , die in diesem API-Abschnitt definiert sind, die Option Bereich hinzufügen aus. Füllen Sie die Felder wie folgt aus, und wählen Sie Bereich hinzufügen aus.
- Bereichsname:
access_as_user
- Wer können zustimmen?: Administratoren und Benutzer
- Anzeigename der Administratorzustimmung:
Access the app as the user
- Beschreibung der Administratorzustimmung:
Allows Teams to call the app's web APIs as the current user.
- Anzeigename der Zustimmung des Benutzers:
Access the app as you
- Beschreibung der Benutzerbewilligung:
Allows Teams to call the app's web APIs as you.
- Status: Aktiviert
- Bereichsname:
Wählen Sie im Abschnitt "Autorisierte Clientanwendungen" die Option "Clientanwendung hinzufügen" aus. Geben Sie eine Client-ID aus der folgenden Liste ein, aktivieren Sie den Bereich unter "Autorisierte Bereiche", und wählen Sie "Anwendung hinzufügen" aus. Wiederholen Sie diesen Vorgang für jede Client-IDs in der Liste.
1fec8e78-bce4-4aaf-ab1b-5451cc387264
(Teams Mobile-/Desktopanwendung)5e3ce6c0-2b1f-4285-8d4b-75ee78787346
(Teams Webanwendung)
Erstellen eines App-Manifests
Das App-Manifest beschreibt, wie die App in Microsoft Teams integriert wird und zum Installieren von Apps erforderlich ist. In diesem Abschnitt verwenden Sie App Studio im Microsoft Teams-Client, um ein Manifest zu generieren.
Wenn Sie App Studio noch nicht in Teams installiert haben, installieren Sie es jetzt.
Starten Sie App Studio in Microsoft Teams, und wählen Sie den Manifest-Editor aus.
Wählen Sie "Neue App erstellen" aus.
Füllen Sie auf der Seite "App-Details" die erforderlichen Felder aus.
Hinweis
Sie können die Standardsymbole im Abschnitt "Branding" verwenden oder Eigene hochladen.
Wählen Sie im linken Menü registerkarten unter "Funktionen" aus.
Wählen Sie unter "Persönliche Registerkarte hinzufügen" die Option "Hinzufügen" aus.
Füllen Sie die Felder wie folgt aus, wobei
YOUR_NGROK_URL
sich die Weiterleitungs-URL befindet, die Sie im vorherigen Abschnitt kopiert haben. Wenn Sie damit fertig sind, wählen Sie Speichern aus.- Name:
Create event
- Entitäts-ID:
createEventTab
- Inhalts-URL:
YOUR_NGROK_URL/newevent
- Name:
Wählen Sie unter "Persönliche Registerkarte hinzufügen" die Option "Hinzufügen" aus.
Füllen Sie die Felder wie folgt aus, wobei
YOUR_NGROK_URL
sich die Weiterleitungs-URL befindet, die Sie im vorherigen Abschnitt kopiert haben. Wenn Sie damit fertig sind, wählen Sie Speichern aus.- Name:
Graph calendar
- Entitäts-ID:
calendarTab
- Inhalts-URL:
YOUR_NGROK_URL
- Name:
Wählen Sie im linken Menü "Domänen und Berechtigungen" unter "Fertig stellen" aus.
Legen Sie die AAD-App-ID auf die Anwendungs-ID aus Ihrer App-Registrierung fest.
Legen Sie das Feld für einmaliges Anmelden auf den Anwendungs-ID-URI aus Ihrer App-Registrierung fest.
Wählen Sie im linken Menü "Testen" und "Verteilen" unter "Fertig stellen" aus. Wählen Sie "Herunterladen" aus.
Erstellen Sie ein neues Verzeichnis im Stammverzeichnis des Projekts mit dem Namen Manifest. Extrahieren Sie den Inhalt der heruntergeladenen ZIP-Datei in dieses Verzeichnis.
Hinzufügen der Azure AD-Authentifizierung
In dieser Übung erweitern Sie die Anwendung aus der vorherigen Übung, um die Single Sign-On-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" }, "Graph": { "Scopes": "https://graph.microsoft.com/.default" }, "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
YOUR_APP_ID
Ihre Anwendungs-ID aus dem Azure-Portal undYOUR_APP_SECRET
ihren geheimen 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
Implementieren Sie zunächst single sign-on im JavaScript-Code der App. Sie verwenden das Microsoft Teams JavaScript SDK, um ein Zugriffstoken abzurufen, das es dem im Teams-Client ausgeführten JavaScript-Code ermöglicht, AJAX-Aufrufe an die Web-API durchzuführen, die Sie später implementieren werden.
Öffnen Sie ./Pages/Index.cshtml, und fügen Sie den folgenden Code innerhalb des
<script>
Tags hinzu.(function () { if (microsoftTeams) { microsoftTeams.initialize(); microsoftTeams.authentication.getAuthToken({ successCallback: (token) => { // TEMPORARY: Display the access token for debugging $('#tab-container').empty(); $('<code/>', { text: token, style: 'word-break: break-all;' }).appendTo('#tab-container'); }, failureCallback: (error) => { renderError(error); } }); } })(); function renderError(error) { $('#tab-container').empty(); $('<h1/>', { text: 'Error' }).appendTo('#tab-container'); $('<code/>', { text: JSON.stringify(error, Object.getOwnPropertyNames(error)), style: 'word-break: break-all;' }).appendTo('#tab-container'); }
Dadurch wird die automatische
microsoftTeams.authentication.getAuthToken
Authentifizierung als der Benutzer aufgerufen, der bei Teams angemeldet ist. In der Regel sind keine Benutzeroberflächenaufforderungen beteiligt, es sei denn, der Benutzer muss zustimmen. Anschließend zeigt der Code das Token auf der Registerkarte an.Speichern Sie Ihre Änderungen, und starten Sie die Anwendung, indem Sie den folgenden Befehl in Der CLI ausführen.
dotnet run
Wichtig
Wenn Sie ngrok neu gestartet haben und ihre ngrok-URL geändert wurde, müssen Sie den ngrok-Wert vor dem Testen an der folgenden Stelle aktualisieren.
- Der Umleitungs-URI in Ihrer App-Registrierung
- Der Anwendungs-ID-URI in Ihrer App-Registrierung
contentUrl
in manifest.jsonvalidDomains
in manifest.jsonresource
in manifest.json
Erstellen Sie eine ZIP-Datei mit manifest.json, color.png und outline.png.
Wählen Sie in Microsoft Teams in der linken Leiste Apps aus, wählen Sie Hochladen einer benutzerdefinierten App aus, und wählen Sie dann Hochladen für mich oder meine Teams aus.
Navigieren Sie zu der ZIP-Datei, die Sie zuvor erstellt haben, und wählen Sie "Öffnen" aus.
Überprüfen Sie die Anwendungsinformationen, und wählen Sie "Hinzufügen" aus.
Die Anwendung wird in Teams geöffnet und zeigt ein Zugriffstoken an.
Wenn Sie das Token kopieren, können Sie es in jwt.mseinfügen. Stellen Sie sicher, dass die Zielgruppe (der aud
Anspruch) Ihre Anwendungs-ID ist und der einzige Bereich (der scp
Anspruch) der access_as_user
von Ihnen erstellte API-Bereich ist. Das bedeutet, dass dieses Token keinen direkten Zugriff auf Microsoft Graph gewährt! Stattdessen muss die Web-API, die Sie bald implementieren werden, dieses Token mithilfe des Im-Auftrag-von-Flusses austauschen, um ein Token abzurufen, das mit Microsoft Graph Aufrufen funktioniert.
Konfigurieren der Authentifizierung in der ASP.NET Core-App
Fügen Sie zunächst die Microsoft Identity Platform-Dienste zur Anwendung hinzu.
Öffnen Sie die Datei ./Startup.cs, und fügen Sie die folgende
using
Anweisung am Anfang der Datei hinzu.using Microsoft.Identity.Web;
Fügen Sie die folgende Zeile direkt vor der
app.UseAuthorization();
Zeile in der FunktionConfigure
hinzu.app.UseAuthentication();
Fügen Sie die folgende Zeile direkt hinter der
endpoints.MapRazorPages();
Zeile in der FunktionConfigure
hinzu.endpoints.MapControllers();
Ersetzen Sie die vorhandene
ConfigureServices
-Funktion durch Folgendes.public void ConfigureServices(IServiceCollection services) { // Use Web API authentication (default JWT bearer token scheme) services.AddMicrosoftIdentityWebApiAuthentication(Configuration) // Enable token acquisition via on-behalf-of flow .EnableTokenAcquisitionToCallDownstreamApi() // Specify that the down-stream API is Graph .AddMicrosoftGraph(Configuration.GetSection("Graph")) // Use in-memory token cache // See https://github.com/AzureAD/microsoft-identity-web/wiki/token-cache-serialization .AddInMemoryTokenCaches(); services.AddRazorPages(); services.AddControllers().AddNewtonsoftJson(); }
Dieser Code konfiguriert die Anwendung so, dass Aufrufe von Web-APIs basierend auf dem JWT-Bearertoken im Header authentifiziert werden
Authorization
können. Außerdem werden die Tokenerfassungsdienste hinzugefügt, die dieses Token über den Im-Auftrag-von-Fluss austauschen können.
Erstellen des Web-API-Controllers
Erstellen Sie ein neues Verzeichnis im Stammverzeichnis des Projekts namens "Controller".
Erstellen Sie eine neue Datei im Verzeichnis "./Controllers" mit dem Namen "CalendarController.cs", und fügen Sie den folgenden Code hinzu.
using System; using System.Collections.Generic; using System.Net; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Microsoft.Identity.Web; using Microsoft.Identity.Web.Resource; using Microsoft.Graph; using TimeZoneConverter; namespace GraphTutorial.Controllers { [ApiController] [Route("[controller]")] [Authorize] public class CalendarController : ControllerBase { private static readonly string[] apiScopes = new[] { "access_as_user" }; private readonly GraphServiceClient _graphClient; private readonly ITokenAcquisition _tokenAcquisition; private readonly ILogger<CalendarController> _logger; public CalendarController(ITokenAcquisition tokenAcquisition, GraphServiceClient graphClient, ILogger<CalendarController> logger) { _tokenAcquisition = tokenAcquisition; _graphClient = graphClient; _logger = logger; } [HttpGet] public async Task<ActionResult<string>> Get() { // This verifies that the access_as_user scope is // present in the bearer token, throws if not HttpContext.VerifyUserHasAnyAcceptedScope(apiScopes); // To verify that the identity libraries have authenticated // based on the token, log the user's name _logger.LogInformation($"Authenticated user: {User.GetDisplayName()}"); try { // TEMPORARY // Get a Graph token via OBO flow var token = await _tokenAcquisition .GetAccessTokenForUserAsync(new[]{ "User.Read", "MailboxSettings.Read", "Calendars.ReadWrite" }); // Log the token _logger.LogInformation($"Access token for Graph: {token}"); return Ok("{ \"status\": \"OK\" }"); } catch (MicrosoftIdentityWebChallengeUserException ex) { _logger.LogError(ex, "Consent required"); // This exception indicates consent is required. // Return a 403 with "consent_required" in the body // to signal to the tab it needs to prompt for consent return new ContentResult { StatusCode = (int)HttpStatusCode.Forbidden, ContentType = "text/plain", Content = "consent_required" }; } catch (Exception ex) { _logger.LogError(ex, "Error occurred"); throw; } } } }
Dadurch wird eine Web-API (
GET /calendar
) implementiert, die über die Registerkarte Teams aufgerufen werden kann. For now it simply tries to exchange the bearer token for a Graph token. Wenn ein Benutzer die Registerkarte zum ersten Mal lädt, tritt ein Fehler auf, da er der App noch nicht zugestimmt hat, den Zugriff auf Microsoft Graph in ihrem Auftrag zuzulassen.Öffnen Sie ./Pages/Index.cshtml, und ersetzen Sie die
successCallback
Funktion durch Folgendes.successCallback: (token) => { // TEMPORARY: Call the Web API fetch('/calendar', { headers: { 'Authorization': `Bearer ${token}` } }).then(response => { response.text() .then(body => { $('#tab-container').empty(); $('<code/>', { text: body }).appendTo('#tab-container'); }); }).catch(error => { console.error(error); renderError(error); }); }
Dadurch wird die Web-API aufgerufen und die Antwort angezeigt.
Speichern Sie die Änderungen, und starten Sie die App neu. Aktualisieren Sie die Registerkarte in Microsoft Teams. Die Seite sollte angezeigt
consent_required
werden.Überprüfen Sie die Protokollausgabe in Ihrer CLI. Beachten Sie zwei Dinge.
- Ein Eintrag wie
Authenticated user: MeganB@contoso.com
. Die Web-API hat den Benutzer basierend auf dem Token authentifiziert, das mit der API-Anforderung gesendet wurde. - Ein Eintrag wie
AADSTS65001: The user or administrator has not consented to use the application with ID...
. Dies wird erwartet, da der Benutzer noch nicht aufgefordert wurde, den angeforderten Microsoft Graph Berechtigungsbereichen zuzustimmen.
- Ein Eintrag wie
Implementieren der Zustimmungsaufforderung
Da die Web-API den Benutzer nicht auffordern kann, muss die Registerkarte Teams eine Eingabeaufforderung implementieren. Dies muss nur einmal für jeden Benutzer erfolgen. Nachdem ein Benutzer seine Zustimmung erteilt hat, muss er den Zugriff auf Ihre Anwendung nicht erneut erklären, es sei denn, er widerruft den Zugriff auf Ihre Anwendung explizit.
Erstellen Sie eine neue Datei im Verzeichnis ./Pages mit dem Namen Authenticate.cshtml.cs, und fügen Sie den folgenden Code hinzu.
using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; namespace GraphTutorial.Pages { public class AuthenticateModel : PageModel { private readonly ILogger<IndexModel> _logger; public string ApplicationId { get; private set; } public string State { get; private set; } public string Nonce { get; private set; } public AuthenticateModel(IConfiguration configuration, ILogger<IndexModel> logger) { _logger = logger; // Read the application ID from the // configuration. This is used to build // the authorization URL for the consent prompt ApplicationId = configuration .GetSection("AzureAd") .GetValue<string>("ClientId"); // Generate a GUID for state and nonce State = System.Guid.NewGuid().ToString(); Nonce = System.Guid.NewGuid().ToString(); } } }
Erstellen Sie eine neue Datei im Verzeichnis ./Pages mit dem Namen Authenticate.cshtml, und fügen Sie den folgenden Code hinzu.
@page <!-- Copyright (c) Microsoft Corporation. Licensed under the MIT License. --> @model AuthenticateModel @section Scripts { <script> (function () { microsoftTeams.initialize(); // Save the state so it can be verified in // AuthComplete.cshtml localStorage.setItem('auth-state', '@Model.State'); // Get the context for tenant ID and login hint microsoftTeams.getContext((context) => { // Set all of the query parameters for an // authorization request const queryParams = { client_id: '@Model.ApplicationId', response_type: 'id_token token', response_mode: 'fragment', scope: 'https://graph.microsoft.com/.default openid', redirect_uri: `${window.location.origin}/authcomplete`, nonce: '@Model.Nonce', state: '@Model.State', login_hint: context.loginHint, }; // Generate the URL const authEndpoint = `https://login.microsoftonline.com/${context.tid}/oauth2/v2.0/authorize?${toQueryString(queryParams)}`; // Browse to the URL window.location.assign(authEndpoint); }); })(); // Helper function to build a query string from an object function toQueryString(queryParams) { let encodedQueryParams = []; for (let key in queryParams) { encodedQueryParams.push(key + '=' + encodeURIComponent(queryParams[key])); } return encodedQueryParams.join('&'); } </script> }
Erstellen Sie eine neue Datei im Verzeichnis ./Pages mit dem Namen "AuthComplete.cshtml", und fügen Sie den folgenden Code hinzu.
@page <!-- Copyright (c) Microsoft Corporation. Licensed under the MIT License. --> @section Scripts { <script> (function () { microsoftTeams.initialize(); const hashParams = getHashParameters(); if (hashParams['error']) { microsoftTeams.authentication.notifyFailure(hashParams['error']); } else if (hashParams['access_token']) { // Check the state parameter const expectedState = localStorage.getItem('auth-state'); if (expectedState !== hashParams['state']) { microsoftTeams.authentication.notifyFailure('StateDoesNotMatch'); } else { // State parameter matches, report success localStorage.removeItem('auth-state'); microsoftTeams.authentication.notifySuccess('Success'); } } else { microsoftTeams.authentication.notifyFailure('NoTokenInResponse'); } })(); // Helper function to generate a hash from // a query string function getHashParameters() { let hashParams = {}; location.hash.substr(1).split('&').forEach(function(item) { let s = item.split('='), k = s[0], v = s[1] && decodeURIComponent(s[1]); hashParams[k] = v; }); return hashParams; } </script> }
Öffnen Sie ./Pages/Index.cshtml, und fügen Sie die folgenden Funktionen innerhalb des
<script>
Tags hinzu.function loadUserCalendar(token, callback) { // Call the API fetch('/calendar', { headers: { 'Authorization': `Bearer ${token}` } }).then(response => { if (response.ok) { // Get the JSON payload response.json() .then(events => { callback(events); }); } else if (response.status === 403) { response.text() .then(body => { // If the API sent 'consent_required' // we need to prompt the user if (body === 'consent_required') { promptForConsent((error) => { if (error) { renderError(error); } else { // Retry API call loadUserCalendar(token, callback); } }); } }); } }).catch(error => { renderError(error); }); } function promptForConsent(callback) { // Cause Teams to popup a window for consent microsoftTeams.authentication.authenticate({ url: `${window.location.origin}/authenticate`, width: 600, height: 535, successCallback: (result) => { callback(null); }, failureCallback: (error) => { callback(error); } }); }
Fügen Sie die folgende Funktion innerhalb des
<script>
Tags hinzu, um ein erfolgreiches Ergebnis aus der Web-API anzuzeigen.function renderCalendar(events) { $('#tab-container').empty(); $('<pre/>').append($('<code/>', { text: JSON.stringify(events, null, 2), style: 'word-break: break-all;' })).appendTo('#tab-container'); }
Ersetzen Sie den vorhandenen
successCallback
durch den folgenden Code.successCallback: (token) => { loadUserCalendar(token, (events) => { renderCalendar(events); }); }
Speichern Sie die Änderungen, und starten Sie die App neu. Aktualisieren Sie die Registerkarte in Microsoft Teams. Sie sollten ein Popupfenster erhalten, in dem Sie die Zustimmung zu den Microsoft Graph Berechtigungsbereichen anfordern. Nach der Annahme sollte die Registerkarte angezeigt
{ "status": "OK" }
werden.Hinweis
Wenn die Registerkarte angezeigt
"FailedToOpenWindow"
wird, deaktivieren Sie Popupblocker in Ihrem Browser, und laden Sie die Seite erneut.Überprüfen Sie die Protokollausgabe. Der Eintrag sollte angezeigt
Access token for Graph
werden. Wenn Sie dieses Token analysieren, werden Sie feststellen, dass es die Microsoft Graph Bereiche enthält, die in appsettings.json konfiguriert sind.
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, ist 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 einer Kalenderansicht
Eine Kalenderansicht ist eine Reihe von Ereignissen aus dem Kalender des Benutzers, die zwischen zwei Zeitpunkten auftreten. Sie verwenden dies, um die Ereignisse des Benutzers für die aktuelle Woche abzurufen.
Öffnen Sie ./Controllers/CalendarController.cs, und fügen Sie der CalendarController-Klasse die folgende Funktion hinzu.
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); }
Fügen Sie die folgende Funktion hinzu, um von Microsoft Graph Aufrufen zurückgegebene Ausnahmen zu behandeln.
private async Task HandleGraphException(Exception exception) { if (exception is MicrosoftIdentityWebChallengeUserException) { _logger.LogError(exception, "Consent required"); // This exception indicates consent is required. // Return a 403 with "consent_required" in the body // to signal to the tab it needs to prompt for consent HttpContext.Response.ContentType = "text/plain"; HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; await HttpContext.Response.WriteAsync("consent_required"); } else if (exception is ServiceException) { var serviceException = exception as ServiceException; _logger.LogError(serviceException, "Graph service error occurred"); HttpContext.Response.ContentType = "text/plain"; HttpContext.Response.StatusCode = (int)serviceException.StatusCode; await HttpContext.Response.WriteAsync(serviceException.Error.ToString()); } else { _logger.LogError(exception, "Error occurred"); HttpContext.Response.ContentType = "text/plain"; HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError; await HttpContext.Response.WriteAsync(exception.ToString()); } }
Ersetzen Sie die vorhandene
Get
-Funktion durch Folgendes.[HttpGet] public async Task<IEnumerable<Event>> Get() { // This verifies that the access_as_user scope is // present in the bearer token, throws if not HttpContext.VerifyUserHasAnyAcceptedScope(apiScopes); // To verify that the identity libraries have authenticated // based on the token, log the user's name _logger.LogInformation($"Authenticated user: {User.GetDisplayName()}"); try { // Get the user's mailbox settings var me = await _graphClient.Me .Request() .Select(u => new { u.MailboxSettings }) .GetAsync(); // Get the start and end of week in user's time // zone var startOfWeek = GetUtcStartOfWeekInTimeZone( DateTime.Today, me.MailboxSettings.TimeZone); var endOfWeek = startOfWeek.AddDays(7); // Set the start and end of the view var viewOptions = new List<QueryOption> { new QueryOption("startDateTime", startOfWeek.ToString("o")), new QueryOption("endDateTime", endOfWeek.ToString("o")) }; // Get the user's calendar view var results = 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=\"{me.MailboxSettings.TimeZone}\"") // Get max 50 per request .Top(50) // Only return fields app will use .Select(e => new { e.Subject, e.Organizer, e.Start, e.End, e.Location }) // Order results chronologically .OrderBy("start/dateTime") .GetAsync(); return results.CurrentPage; } catch (Exception ex) { await HandleGraphException(ex); return null; } }
Überprüfen Sie die Änderungen. Diese neue Version der Funktion:
- Gibt
IEnumerable<Event>
anstelle vonstring
. - Ruft die Postfacheinstellungen des Benutzers mithilfe von Microsoft Graph ab.
- Verwendet die Zeitzone des Benutzers, um den Anfang und das Ende der aktuellen Woche zu berechnen.
- Ruft eine Kalenderansicht ab
- Verwendet die
.Header()
Funktion, um einen Header einzuschließen,Prefer: outlook.timezone
wodurch die Start- und Endzeiten der zurückgegebenen Ereignisse in die Zeitzone des Benutzers konvertiert werden. - Verwendet die
.Top()
Funktion, um höchstens 50 Ereignisse anzufordern. - Verwendet die
.Select()
Funktion, um nur die von der App verwendeten Felder anzufordern. - Verwendet die
OrderBy()
Funktion, um die Ergebnisse nach der Startzeit zu sortieren.
- Verwendet die
- Gibt
Speichern Sie die Änderungen, und starten Sie die App neu. Aktualisieren Sie die Registerkarte in Microsoft Teams. Die App zeigt eine JSON-Auflistung der Ereignisse an.
Anzeigen der Ergebnisse
Jetzt können Sie die Liste der Ereignisse benutzerfreundlicher anzeigen.
Öffnen Sie ./Pages/Index.cshtml, und fügen Sie die folgenden Funktionen innerhalb des
<script>
Tags hinzu.function renderSubject(subject) { if (!subject || subject.length <= 0) { subject = '<No subject>'; } return $('<div/>', { class: 'ms-fontSize-18 ms-fontWeight-bold', text: subject }); } function renderOrganizer(organizer) { return $('<div/>', { class: 'ms-fontSize-14 ms-fontWeight-semilight', text: organizer.emailAddress.name }).append($('<i/>', { class: 'ms-Icon ms-Icon--PartyLeader', style: 'margin-right: 10px;' })); } function renderTimeSpan(start, end) { return $('<div/>', { class: 'ms-fontSize-14 ms-fontWeight-semilight', text: `${formatDateTime(start.dateTime)} - ${formatDateTime(end.dateTime)}` }).append($('<i/>', { class: 'ms-Icon ms-Icon--DateTime2', style: 'margin-right: 10px;' })); } function formatDateTime(dateTime) { const date = new Date(dateTime); // Format like 10/14/2020 4:00 PM let hours = date.getHours(); const minutes = date.getMinutes(); const ampm = hours >= 12 ? 'PM' : 'AM'; hours = hours % 12; hours = hours ? hours : 12; const minStr = minutes < 10 ? `0${minutes}` : minutes; return `${date.getMonth()+1}/${date.getDate()}/${date.getFullYear()} ${hours}:${minStr} ${ampm}`; } function renderLocation(location) { if (!location || location.displayName.length <= 0) { return null; } return $('<div/>', { class: 'ms-fontSize-14 ms-fontWeight-semilight', text: location.displayName }).append($('<i/>', { class: 'ms-Icon ms-Icon--MapPin', style: 'margin-right: 10px;' })); }
Ersetzen Sie die vorhandene
renderCalendar
-Funktion durch Folgendes.function renderCalendar(events) { $('#tab-container').empty(); // Add title $('<div/>', { class: 'tab-title ms-fontSize-42', text: 'Week at a glance' }).appendTo('#tab-container'); // Render each event events.map(event => { const eventCard = $('<div/>', { class: 'event-card ms-depth-4', }); eventCard.append(renderSubject(event.subject)); eventCard.append(renderOrganizer(event.organizer)); eventCard.append(renderTimeSpan(event.start, event.end)); const location = renderLocation(event.location); if (location) { eventCard.append(location); } eventCard.appendTo('#tab-container'); }); }
Speichern Sie die Änderungen, und starten Sie die App neu. Aktualisieren Sie die Registerkarte in Microsoft Teams. Die App zeigt Ereignisse im Kalender des Benutzers an.
Erstellen eines neuen Ereignisses
In diesem Abschnitt fügen Sie die Möglichkeit hinzu, Ereignisse im Kalender des Benutzers zu erstellen.
Erstellen der neuen Ereignisregisterkarte
Erstellen Sie eine neue Datei im Verzeichnis "./Pages" mit dem Namen "NewEvent.cshtml", und fügen Sie den folgenden Code hinzu.
@page <!-- Copyright (c) Microsoft Corporation. Licensed under the MIT License. --> @{ ViewData["Title"] = "New event"; } <div class="form-container"> <form id="newEventForm"> <div class="ms-Grid" dir="ltr"> <div class="ms-Grid-row"> <div class="ms-Grid-col ms-sm12"> <label class="ms-fontWeight-semibold form-label" for="subject">Subject</label> <input class="form-input" type="text" id="subject" name="subject" /> </div> </div> <div class="ms-Grid-row"> <div class="ms-Grid-col ms-sm12"> <label class="ms-fontWeight-semibold form-label" for="attendees">Attendees</label> <input class="form-input" type="text" id="attendees" name="attendees" placeholder="Enter email addresses of attendees. Separate multiple with ';'. Leave blank for no attendees." /> </div> </div> <div class="ms-Grid-row"> <div class="ms-Grid-col ms-sm6"> <label class="ms-fontWeight-semibold form-label" for="start">Start</label> <input class="form-input" type="datetime-local" id="start" name="start" /> </div> <div class="ms-Grid-col ms-sm6"> <label class="ms-fontWeight-semibold form-label" for="end">End</label> <input class="form-input" type="datetime-local" id="end" name="end" /> </div> </div> <div class="ms-Grid-row"> <div class="ms-Grid-col ms-sm12"> <label class="ms-fontWeight-semibold form-label" for="body">Body</label> <textarea class="form-input" id="body" name="body" rows="4"></textarea> </div> </div> <input class="form-button" type="submit" value="Create"/> </div> </form> <div class="ms-depth-16 result-panel"></div> </div> @section Scripts { <script> (function () { if (microsoftTeams) { microsoftTeams.initialize(); } $('#newEventForm').on('submit', async (e) => { e.preventDefault(); $('.result-panel').empty(); $('.result-panel').hide(); const formData = new FormData(newEventForm); // Basic validation // Require subject, start, and end const subject = formData.get('subject'); const start = formData.get('start'); const end = formData.get('end'); if (subject.length <= 0 || start.length <= 0 || end.length <= 0) { $('<div/>', { class: 'error-msg', text: 'Subject, Start, and End are required.' }).appendTo('.result-panel'); $('.result-panel').show(); return; } // Get the auth token from Teams microsoftTeams.authentication.getAuthToken({ successCallback: (token) => { createEvent(token, formData); }, failureCallback: (error) => { $('<div/>', { class: 'error-msg', text: `Error getting token: ${error}` }).appendTo('.result-panel'); $('.result-panel').show(); } }); }); })(); async function createEvent(token, formData) { // Convert the form to a JSON payload jsonFormData = formDataToJson(); // Post the payload to the web API const response = await fetch('/calendar', { headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, method: 'POST', body: jsonFormData }); if (response.ok) { $('<div/>', { class: 'success-msg', text: 'Event added to your calendar' }).appendTo('.result-panel'); $('.result-panel').show(); } else { const error = await response.text(); $('<div/>', { class: 'error-msg', text: `Error creating event: ${error}` }).appendTo('.result-panel'); $('.result-panel').show(); } } // Helper method to serialize the form fields // as JSON function formDataToJson() { const array = $('#newEventForm').serializeArray(); const jsonObj = {}; array.forEach((kvp) => { jsonObj[kvp.name] = kvp.value; }); return JSON.stringify(jsonObj); } </script> }
Dadurch wird ein einfaches Formular implementiert und JavaScript hinzugefügt, um die Formulardaten an die Web-API zu senden.
Implementieren der Web-API
Erstellen Sie ein neues Verzeichnis mit dem Namen Models im Stammverzeichnis des Projekts.
Erstellen Sie eine neue Datei im Verzeichnis "./Models" mit dem Namen "NewEvent.cs", und fügen Sie den folgenden Code hinzu.
namespace GraphTutorial.Models { public class NewEvent { public string Subject { get; set; } public string Attendees { get; set; } public string Start { get; set; } public string End { get; set; } public string Body { get; set; } } }
Öffnen Sie "./Controllers/CalendarController.cs", und fügen Sie die folgende
using
Anweisung am Anfang der Datei hinzu.using GraphTutorial.Models;
Fügen Sie der CalendarController-Klasse die folgende Funktion hinzu.
[HttpPost] public async Task<string> Post(NewEvent newEvent) { HttpContext.VerifyUserHasAnyAcceptedScope(apiScopes); try { // Get the user's mailbox settings var me = await _graphClient.Me .Request() .Select(u => new { u.MailboxSettings }) .GetAsync(); // Create a Graph Event var graphEvent = new Event { Subject = newEvent.Subject, Start = new DateTimeTimeZone { DateTime = newEvent.Start, TimeZone = me.MailboxSettings.TimeZone }, End = new DateTimeTimeZone { DateTime = newEvent.End, TimeZone = me.MailboxSettings.TimeZone } }; // If there are attendees, add them if (!string.IsNullOrEmpty(newEvent.Attendees)) { var attendees = new List<Attendee>(); var emailArray = newEvent.Attendees.Split(';'); foreach (var email in emailArray) { attendees.Add(new Attendee { Type = AttendeeType.Required, EmailAddress = new EmailAddress { Address = email } }); } graphEvent.Attendees = attendees; } // If there is a body, add it if (!string.IsNullOrEmpty(newEvent.Body)) { graphEvent.Body = new ItemBody { ContentType = BodyType.Text, Content = newEvent.Body }; } // Create the event await _graphClient.Me .Events .Request() .AddAsync(graphEvent); return "success"; } catch (Exception ex) { await HandleGraphException(ex); return null; } }
Dadurch wird ein HTTP POST an die Web-API mit den Feldern des Formulars ermöglicht.
Speichern Sie alle Änderungen, und starten Sie die Anwendung neu. Aktualisieren Sie die App in Microsoft Teams, und wählen Sie die Registerkarte "Ereignis erstellen" aus. Füllen Sie das Formular aus, und wählen Sie "Erstellen" aus, um dem Kalender des Benutzers ein Ereignis hinzuzufügen.
Herzlichen Glückwunsch!
Sie haben die Microsoft Teams-App mit Microsoft Graph Lernprogramm 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.