Erstellen von auf Angular basierten Single-Page-Apps mit Microsoft Graph
In diesem Lernprogramm erfahren Sie, wie Sie eine Angular einzelseitige App erstellen, die Microsoft Graph 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.
Voraussetzungen
Bevor Sie mit diesem Lernprogramm beginnen, sollten SieNode.js auf Ihrem Entwicklungscomputer installiert haben. Wenn Sie nicht über Node.js verfügen, finden Sie unter dem vorherigen Link Downloadoptionen.
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 Node Version 14.15.0 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 auf Angular basierten Single-Page-App
In diesem Abschnitt erstellen Sie ein neues Angular Projekt.
Öffnen Sie Die Befehlszeilenschnittstelle (CLI), navigieren Sie zu einem Verzeichnis, in dem Sie über die Berechtigung zum Erstellen von Dateien verfügen, und führen Sie die folgenden Befehle aus, um das Angular CLI-Tool zu installieren und eine neue Angular-App zu erstellen.
npm install -g @angular/cli ng new graph-tutorial
Die Angular CLI fordert weitere Informationen an. Beantworten Sie die Eingabeaufforderungen wie folgt.
? Would you like to add Angular routing? Yes ? Which stylesheet format would you like to use? CSS
Wechseln Sie nach Abschluss des Befehls zum
graph-tutorial
Verzeichnis in der CLI, und führen Sie den folgenden Befehl aus, um einen lokalen Webserver zu starten.ng serve --open
Ihr Standardbrowser wird mit einer standardmäßigen Angular Seite geöffnethttps://localhost:4200/. Wenn Ihr Browser nicht geöffnet wird, öffnen Sie ihn, und navigieren Sie, um zu https://localhost:4200/ überprüfen, ob die neue App funktioniert.
Hinzufügen von Node-Paketen
Bevor Sie fortfahren, installieren Sie einige zusätzliche Pakete, die Sie später verwenden werden:
- ng-bootstrap für die Verwendung von Bootstrap-Komponenten aus Angular.
- moment formatting dates and times.
- windows-iana
- msal-angular zum Authentifizieren bei Azure Active Directory und Abrufen von Zugriffstoken.
- microsoft-graph-client for making calls to Microsoft Graph.
Führen Sie die folgenden Befehle in Der CLI aus.
ng add @ng-bootstrap/ng-bootstrap npm install @azure/msal-browser@2.16.1 @azure/msal-angular@2.0.2 npm install date-fns@2.23.0 date-fns-tz@1.1.6 windows-iana@5.0.2 npm install @microsoft/microsoft-graph-client@3.0.0 npm install @microsoft/microsoft-graph-types --save-dev
Entwerfen der App
In diesem Abschnitt erstellen Sie die Benutzeroberfläche für die App.
Öffnen Sie ./src/styles.css , und fügen Sie die folgenden Zeilen hinzu.
@import "~bootstrap/dist/css/bootstrap.css"; /* Add padding for the nav bar */ body { padding-top: 4.5rem; } /* Style debug info in alerts */ .alert-pre { word-wrap: break-word; word-break: break-all; white-space: pre-wrap; } /* Add padding to user avatar link */ .avatar-link { padding-top: .25em; padding-bottom: .25em; }
Erstellen Sie eine neue Datei im Ordner "./src/app " mit dem Namen " user.ts", und fügen Sie den folgenden Code hinzu.
export class User { displayName!: string; email!: string; avatar!: string; timeZone!: string; }
Generieren Sie eine Angular Komponente für die obere Navigation auf der Seite. Führen Sie in Der CLI den folgenden Befehl aus.
ng generate component nav-bar
Öffnen Sie nach Abschluss des Befehls ./src/app/nav-bar/nav-bar.component.ts , und ersetzen Sie den Inhalt durch Folgendes.
import { Component, OnInit } from '@angular/core'; import { User } from '../user'; @Component({ selector: 'app-nav-bar', templateUrl: './nav-bar.component.html', styleUrls: ['./nav-bar.component.css'] }) export class NavBarComponent implements OnInit { // Should the collapsed nav show? showNav: boolean = false; // Is a user logged in? authenticated: boolean = false; // The user user?: User = undefined; constructor() { } ngOnInit() { } // Used by the Bootstrap navbar-toggler button to hide/show // the nav in a collapsed state toggleNavBar(): void { this.showNav = !this.showNav; } signIn(): void { // Temporary this.authenticated = true; this.user = { displayName: 'Adele Vance', email: 'AdeleV@contoso.com', avatar: '/assets/no-profile-photo.png', timeZone: '' }; } signOut(): void { // Temporary this.authenticated = false; this.user = undefined; } }
Öffnen Sie ./src/app/nav-bar/nav-bar.component.html , und ersetzen Sie den Inhalt durch Folgendes.
<nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark"> <div class="container"> <a routerLink="/" class="navbar-brand">Angular Graph Tutorial</a> <button class="navbar-toggler" type="button" (click)="toggleNavBar()" [attr.aria-expanded]="showNav" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" [class.show]="showNav" id="navbarCollapse"> <ul class="navbar-nav mr-auto"> <li class="nav-item"> <a routerLink="/" class="nav-link" routerLinkActive="active">Home</a> </li> <li *ngIf="authenticated" class="nav-item"> <a routerLink="/calendar" class="nav-link" routerLinkActive="active">Calendar</a> </li> </ul> <ul class="navbar-nav justify-content-end"> <li class="nav-item"> <a class="nav-link" href="https://docs.microsoft.com/graph/overview" target="_blank">Docs</a> </li> <li *ngIf="authenticated" ngbDropdown placement="bottom-right" class="nav-item"> <a ngbDropdownToggle id="userMenu" class="nav-link avatar-link" role="button" aria-haspopup="true" aria-expanded="false"> <img src="{{user != null ? user.avatar : ''}}" class="rounded-circle align-self-center mr-2" style="width: 32px;"> </a> <div ngbDropdownMenu aria-labelledby="userMenu" class="dropdown-menu-right"> <h5 class="dropdown-item-text mb-0">{{user != null ? user.displayName : ''}}</h5> <p class="dropdown-item-text text-muted mb-0">{{user != null ? user.email : ''}}</p> <div class="dropdown-divider"></div> <button class="dropdown-item" role="button" (click)="signOut()">Sign Out</button> </div> </li> <li *ngIf="!authenticated" class="nav-item"> <button class="btn btn-link nav-link border-0" role="button" (click)="signIn()">Sign In</button> </li> </ul> </div> </div> </nav>
Erstellen Sie eine Startseite für die App. Führen Sie den folgenden Befehl in Der CLI aus.
ng generate component home
Öffnen Sie nach Abschluss des Befehls ./src/app/home/home.component.ts , und ersetzen Sie den Inhalt durch Folgendes.
import { Component, OnInit } from '@angular/core'; import { User } from '../user'; @Component({ selector: 'app-home', templateUrl: './home.component.html', styleUrls: ['./home.component.css'] }) export class HomeComponent implements OnInit { // Is a user logged in? authenticated: boolean = false; // The user user?: User = undefined; constructor() { } ngOnInit() { } signIn(): void { // Temporary this.authenticated = true; this.user = { displayName: 'Adele Vance', email: 'AdeleV@contoso.com', avatar: '', timeZone: '' }; } }
Öffnen Sie ./src/app/home/home.component.html , und ersetzen Sie den Inhalt durch Folgendes.
<div class="jumbotron"> <h1>Angular Graph Tutorial</h1> <p class="lead">This sample app shows how to use the Microsoft Graph API from Angular</p> <div *ngIf="authenticated; then welcomeUser else signInPrompt"></div> <ng-template #welcomeUser> <h4>Welcome {{ user != null ? user.displayName : '' }}!</h4> <p>Use the navigation bar at the top of the page to get started.</p> </ng-template> <ng-template #signInPrompt> <button class="btn btn-primary btn-large" role="button" (click)="signIn()">Click here to sign in</button> </ng-template> </div>
Erstellen Sie eine einfache
Alert
Klasse. Erstellen Sie eine neue Datei im Verzeichnis "./src/app " mit dem Namen "alert.ts", und fügen Sie den folgenden Code hinzu.export class Alert { type!: string; message!: string; debug!: string; }
Erstellen Sie einen Benachrichtigungsdienst, den die App zum Anzeigen von Nachrichten für den Benutzer verwenden kann. Führen Sie in Der CLI den folgenden Befehl aus.
ng generate service alerts
Öffnen Sie ./src/app/alerts.service.ts , und ersetzen Sie den Inhalt durch Folgendes.
import { Injectable } from '@angular/core'; import { Alert } from './alert'; @Injectable({ providedIn: 'root' }) export class AlertsService { alerts: Alert[] = []; addError(message: string, debug?: string) { this.alerts.push({message: message, debug: debug ?? '', type: 'danger'}); } addSuccess(message: string, debug?: string) { this.alerts.push({message: message, debug: debug ?? '', type: 'success'}); } remove(alert: Alert) { this.alerts.splice(this.alerts.indexOf(alert), 1); } }
Generieren Sie eine Warnungskomponente, um Warnungen anzuzeigen. Führen Sie in Der CLI den folgenden Befehl aus.
ng generate component alerts
Öffnen Sie nach Abschluss des Befehls ./src/app/alerts/alerts.component.ts , und ersetzen Sie den Inhalt durch Folgendes.
import { Component, OnInit } from '@angular/core'; import { AlertsService } from '../alerts.service'; import { Alert } from '../alert'; @Component({ selector: 'app-alerts', templateUrl: './alerts.component.html', styleUrls: ['./alerts.component.css'] }) export class AlertsComponent implements OnInit { constructor(public alertsService: AlertsService) { } ngOnInit() { } close(alert: Alert) { this.alertsService.remove(alert); } }
Öffnen Sie ./src/app/alerts/alerts.component.html , und ersetzen Sie den Inhalt durch Folgendes.
<div *ngFor="let alert of alertsService.alerts"> <ngb-alert type="{{alert.type}}" (close)="close(alert)"> {{alert.message}} <pre *ngIf="alert.debug" class="alert-pre border bg-light p-2 mt-2"><code>{{alert.debug}}</code></pre> </ngb-alert> </div>
Öffnen Sie ./src/app/app-routing.module.ts , und ersetzen Sie die
const routes: Routes = [];
Zeile durch den folgenden Code.import { HomeComponent } from './home/home.component'; const routes: Routes = [ { path: '', component: HomeComponent }, ];
Öffnen Sie ./src/app/app.component.html , und ersetzen Sie den gesamten Inhalt durch Folgendes.
<app-nav-bar></app-nav-bar> <main role="main" class="container"> <app-alerts></app-alerts> <router-outlet></router-outlet> </main>
Fügen Sie eine Bilddatei Ihrer Wahl namens no-profile-photo.png im Verzeichnis ./src/assets hinzu. Dieses Bild wird als Foto des Benutzers verwendet, wenn der Benutzer kein Foto in Microsoft Graph hat.
Speichern Sie alle Änderungen, und aktualisieren Sie die Seite. 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
Angular 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
Single-page application (SPA)
fest, und legen Sie den Wert aufhttp://localhost:4200
fest.
- Legen Sie Name auf
Wählen Sie Registrieren aus. Kopieren Sie auf der Seite Angular Graph Lernprogramm den Wert der Anwendungs-ID (Client-ID), und speichern Sie ihn. Sie benötigen ihn im nächsten Schritt.
Hinzufügen der Azure AD-Authentifizierung
In dieser Übung erweitern Sie die Anwendung aus der vorherigen Übung, um die Authentifizierung mit Azure AD zu unterstützen. Dies ist erforderlich, um das erforderliche OAuth-Zugriffstoken zum Aufrufen der Microsoft Graph abzurufen. In diesem Schritt integrieren Sie die Microsoft-Authentifizierungsbibliothek für Angular in die Anwendung.
Erstellen Sie eine neue Datei im Verzeichnis ./src mit dem Namen "oauth.ts", und fügen Sie den folgenden Code hinzu.
export const OAuthSettings = { appId: 'YOUR_APP_ID_HERE', redirectUri: 'http://localhost:4200', scopes: [ "user.read", "mailboxsettings.read", "calendars.readwrite" ] };
Ersetzen Sie
YOUR_APP_ID_HERE
dies durch die Anwendungs-ID aus dem Anwendungsregistrierungsportal.Wichtig
Wenn Sie die Quellcodeverwaltung wie Git verwenden, wäre es jetzt ein guter Zeitpunkt, die Datei "oauth.ts " aus der Quellcodeverwaltung auszuschließen, um zu vermeiden, dass versehentlich Ihre App-ID offengelegt wird.
Öffnen Sie ./src/app/app.module.ts , und fügen Sie die folgenden
import
Anweisungen am Anfang der Datei hinzu.import { FormsModule } from '@angular/forms'; import { IPublicClientApplication, PublicClientApplication, BrowserCacheLocation } from '@azure/msal-browser'; import { MsalModule, MsalService, MSAL_INSTANCE } from '@azure/msal-angular'; import { OAuthSettings } from '../oauth';
Fügen Sie die folgende Funktion unterhalb der
import
Anweisungen hinzu.let msalInstance: IPublicClientApplication | undefined = undefined; export function MSALInstanceFactory(): IPublicClientApplication { msalInstance = msalInstance ?? new PublicClientApplication({ auth: { clientId: OAuthSettings.appId, redirectUri: OAuthSettings.redirectUri, postLogoutRedirectUri: OAuthSettings.redirectUri }, cache: { cacheLocation: BrowserCacheLocation.LocalStorage, } }); return msalInstance; }
Fügen Sie
MsalModule
dem Array innerhalb derimports
@NgModule
Deklaration undFormsModule
dem Array hinzu.imports: [ BrowserModule, FormsModule, AppRoutingModule, NgbModule, MsalModule ],
Fügen Sie das
MSALInstanceFactory
undMsalService
demproviders
Array innerhalb der Deklaration hinzu@NgModule
.providers: [ { provide: MSAL_INSTANCE, useFactory: MSALInstanceFactory }, MsalService ],
Implementieren der Anmeldung
In diesem Abschnitt erstellen Sie einen Authentifizierungsdienst und implementieren die Anmeldung und Abmeldung.
Führen Sie den folgenden Befehl in Der CLI aus.
ng generate service auth
Indem Sie dafür einen Dienst erstellen, können Sie ihn ganz einfach in alle Komponenten einfügen, die Zugriff auf Authentifizierungsmethoden benötigen.
Öffnen Sie nach Abschluss des Befehls ./src/app/auth.service.ts , und ersetzen Sie den Inhalt durch den folgenden Code.
import { Injectable } from '@angular/core'; import { MsalService } from '@azure/msal-angular'; import { InteractionType, PublicClientApplication } from '@azure/msal-browser'; import { AlertsService } from './alerts.service'; import { OAuthSettings } from '../oauth'; import { User } from './user'; @Injectable({ providedIn: 'root' }) export class AuthService { public authenticated: boolean; public user?: User; constructor( private msalService: MsalService, private alertsService: AlertsService) { this.authenticated = false; this.user = undefined; } // Prompt the user to sign in and // grant consent to the requested permission scopes async signIn(): Promise<void> { const result = await this.msalService .loginPopup(OAuthSettings) .toPromise() .catch((reason) => { this.alertsService.addError('Login failed', JSON.stringify(reason, null, 2)); }); if (result) { this.msalService.instance.setActiveAccount(result.account); this.authenticated = true; // Temporary placeholder this.user = new User(); this.user.displayName = 'Adele Vance'; this.user.email = 'AdeleV@contoso.com'; this.user.avatar = '/assets/no-profile-photo.png'; // Temporary to display token in an error box this.alertsService.addSuccess('Token acquired', result.accessToken); } } // Sign out async signOut(): Promise<void> { await this.msalService.logout().toPromise(); this.user = undefined; this.authenticated = false; } }
Öffnen Sie ./src/app/nav-bar/nav-bar.component.ts , und ersetzen Sie den Inhalt durch Folgendes.
import { Component, OnInit } from '@angular/core'; import { AuthService } from '../auth.service'; import { User } from '../user'; @Component({ selector: 'app-nav-bar', templateUrl: './nav-bar.component.html', styleUrls: ['./nav-bar.component.css'] }) export class NavBarComponent implements OnInit { // Should the collapsed nav show? showNav: boolean = false; // Is a user logged in? get authenticated(): boolean { return this.authService.authenticated; } // The user get user(): User | undefined { return this.authService.user; } constructor(private authService: AuthService) { } ngOnInit() { } // Used by the Bootstrap navbar-toggler button to hide/show // the nav in a collapsed state toggleNavBar(): void { this.showNav = !this.showNav; } async signIn(): Promise<void> { await this.authService.signIn(); } signOut(): void { this.authService.signOut(); } }
Öffnen Sie ./src/app/home/home.component.ts , und ersetzen Sie den Inhalt durch Folgendes.
Speichern Sie Ihre Änderungen, und aktualisieren Sie den Browser. Klicken Sie auf die Schaltfläche "Hier klicken", um sich anzumelden , und Sie sollten zu https://login.microsoftonline.com
umgeleitet werden. Melden Sie sich mit Ihrem Microsoft-Konto an, und stimmen Sie den angeforderten Berechtigungen zu. Die App-Seite sollte mit dem Token aktualisiert werden.
Benutzerdetails abrufen
Derzeit legt der Authentifizierungsdienst konstanten Werte für den Anzeigenamen und die E-Mail-Adresse des Benutzers fest. Nachdem Sie nun über ein Zugriffstoken verfügen, können Sie Benutzerdetails von Microsoft Graph abrufen, damit diese Werte dem aktuellen Benutzer entsprechen.
Öffnen Sie ./src/app/auth.service.ts , und fügen Sie die folgenden
import
Anweisungen am Anfang der Datei hinzu.import { Client } from '@microsoft/microsoft-graph-client'; import { AuthCodeMSALBrowserAuthenticationProvider } from '@microsoft/microsoft-graph-client/authProviders/authCodeMsalBrowser'; import * as MicrosoftGraph from '@microsoft/microsoft-graph-types';
Fügen Sie der Klasse mit dem
AuthService
Namen eine Eigenschaft hinzugraphClient
.public graphClient?: Client;
Fügen Sie eine neue Funktion zur
AuthService
-Klasse mit dem NamengetUser
hinzu.private async getUser(): Promise<User | undefined> { if (!this.authenticated) return undefined; const graphClient = Client.init({ // Initialize the Graph client with an auth // provider that requests the token from the // auth service authProvider: async(done) => { const token = await this.getAccessToken() .catch((reason) => { done(reason, null); }); if (token) { done(null, token); } else { done("Could not get an access token", null); } } }); // Get the user from Graph (GET /me) const graphUser: MicrosoftGraph.User = await graphClient .api('/me') .select('displayName,mail,mailboxSettings,userPrincipalName') .get(); const user = new User(); user.displayName = graphUser.displayName ?? ''; // Prefer the mail property, but fall back to userPrincipalName user.email = graphUser.mail ?? graphUser.userPrincipalName ?? ''; user.timeZone = graphUser.mailboxSettings?.timeZone ?? 'UTC'; // Use default avatar user.avatar = '/assets/no-profile-photo.png'; return user; }
Suchen Und entfernen Sie den folgenden Code aus der
signIn
Methode.// Temporary placeholder this.user = new User(); this.user.displayName = "Adele Vance"; this.user.email = "AdeleV@contoso.com"; this.user.avatar = '/assets/no-profile-photo.png'; // Temporary to display token in an error box this.alertsService.addSuccess('Token acquired', result);
Fügen Sie an seiner Stelle den folgenden Code hinzu.
this.user = await this.getUser();
Dieser neue Code verwendet das Microsoft Graph SDK, um die Details des Benutzers abzurufen, und erstellt dann ein
User
Objekt mithilfe von Werten, die vom API-Aufruf zurückgegeben werden.Ändern Sie die
constructor
AuthService
Klasse so, dass überprüft wird, ob der Benutzer bereits angemeldet ist, und laden Sie ggf. seine Details. Ersetzen Sie das vorhandeneconstructor
durch Folgendes.constructor( private msalService: MsalService, private alertsService: AlertsService) { this.authenticated = this.msalService.instance .getAllAccounts().length > 0; this.getUser().then((user) => {this.user = user}); }
Wenn Sie nun Ihre Änderungen speichern und die App starten, sollten Sie nach der Anmeldung wieder auf der Startseite enden, aber die Benutzeroberfläche sollte sich ändern, 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.
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, mit dem die App im Namen des Benutzers auf die Microsoft-Graph zugreifen kann.
Dieses Token ist jedoch nur kurzzeitig verfügbar. Das Token läuft eine Stunde nach der Ausstellung ab. Da die App die MSAL-Bibliothek verwendet, müssen Sie keine Tokenspeicher- oder Aktualisierungslogik implementieren. Das MsalService
Token wird im Browserspeicher zwischengespeichert. Die acquireTokenSilent
Methode überprüft zuerst das zwischengespeicherte Token und gibt es zurück, wenn es nicht abgelaufen ist. Wenn es abgelaufen ist, wird eine automatische Anforderung zum Abrufen einer neuen Anforderung gesendet.
Kalenderansicht abrufen
In dieser Übung integrieren Sie die Microsoft Graph in die Anwendung. Für diese Anwendung verwenden Sie die Microsoft-Graph-Clientbibliothek, um Aufrufe an Microsoft Graph zu tätigen.
Abrufen von Kalenderereignissen von Outlook
Fügen Sie einen neuen Dienst hinzu, um alle Ihre Graph Anrufe zu speichern. Führen Sie den folgenden Befehl in Der CLI aus.
ng generate service graph
Genau wie bei dem zuvor erstellten Authentifizierungsdienst können Sie durch das Erstellen eines Diensts diesen in alle Komponenten einfügen, die Zugriff auf Microsoft Graph benötigen.
Öffnen Sie nach Abschluss des Befehls ./src/app/graph.service.ts , und ersetzen Sie den Inhalt durch Folgendes.
import { Injectable } from '@angular/core'; import * as MicrosoftGraph from '@microsoft/microsoft-graph-types'; import { AuthService } from './auth.service'; import { AlertsService } from './alerts.service'; @Injectable({ providedIn: 'root' }) export class GraphService { constructor( private authService: AuthService, private alertsService: AlertsService) {} async getCalendarView(start: string, end: string, timeZone: string): Promise<MicrosoftGraph.Event[] | undefined> { if (!this.authService.graphClient) { this.alertsService.addError('Graph client is not initialized.'); return undefined; } try { // GET /me/calendarview?startDateTime=''&endDateTime='' // &$select=subject,organizer,start,end // &$orderby=start/dateTime // &$top=50 const result = await this.authService.graphClient .api('/me/calendarview') .header('Prefer', `outlook.timezone="${timeZone}"`) .query({ startDateTime: start, endDateTime: end }) .select('subject,organizer,start,end') .orderby('start/dateTime') .top(50) .get(); return result.value; } catch (error) { this.alertsService.addError('Could not get events', JSON.stringify(error, null, 2)); } return undefined; } }
Überlegen Sie sich, was dieser Code macht.
- Es initialisiert einen Graph-Client im Konstruktor für den Dienst.
- Es implementiert eine
getCalendarView
Funktion, die den Graph Client wie folgt verwendet:- Die URL, die aufgerufen wird, lautet
/me/calendarview
. - Die
header
Methode enthält denPrefer: outlook.timezone
Header, wodurch sich die Start- und Endzeiten der zurückgegebenen Ereignisse in der bevorzugten Zeitzone des Benutzers befinden. - Die
query
Methode fügt diestartDateTime
Parameter hinzu undendDateTime
definiert das Zeitfenster für die Kalenderansicht. - Die
select
Methode beschränkt die für jedes Ereignis zurückgegebenen Felder auf die Felder, die tatsächlich von der Ansicht verwendet werden. - Die
orderby
Methode sortiert die Ergebnisse nach Startzeit.
- Die URL, die aufgerufen wird, lautet
Erstellen Sie eine Angular Komponente, um diese neue Methode aufzurufen und die Ergebnisse des Aufrufs anzuzeigen. Führen Sie den folgenden Befehl in Der CLI aus.
ng generate component calendar
Fügen Sie nach Abschluss des Befehls die Komponente dem
routes
Array in "./src/app/app-routing.module.ts" hinzu.import { CalendarComponent } from './calendar/calendar.component'; const routes: Routes = [ { path: '', component: HomeComponent }, { path: 'calendar', component: CalendarComponent }, ];
Öffnen Sie ./src/app/calendar/calendar.component.ts , und ersetzen Sie den Inhalt durch Folgendes.
import { Component, OnInit } from '@angular/core'; import { parseISO } from 'date-fns'; import { endOfWeek, startOfWeek } from 'date-fns/esm'; import { zonedTimeToUtc } from 'date-fns-tz'; import { findIana } from 'windows-iana'; import * as MicrosoftGraph from '@microsoft/microsoft-graph-types'; import { AuthService } from '../auth.service'; import { GraphService } from '../graph.service'; import { AlertsService } from '../alerts.service'; @Component({ selector: 'app-calendar', templateUrl: './calendar.component.html', styleUrls: ['./calendar.component.css'] }) export class CalendarComponent implements OnInit { public events?: MicrosoftGraph.Event[]; constructor( private authService: AuthService, private graphService: GraphService, private alertsService: AlertsService) { } async ngOnInit() { // Convert the user's timezone to IANA format const ianaName = findIana(this.authService.user?.timeZone ?? 'UTC'); const timeZone = ianaName![0].valueOf() || this.authService.user?.timeZone || 'UTC'; // Get midnight on the start of the current week in the user's timezone, // but in UTC. For example, for Pacific Standard Time, the time value would be // 07:00:00Z const now = new Date(); const weekStart = zonedTimeToUtc(startOfWeek(now), timeZone); const weekEnd = zonedTimeToUtc(endOfWeek(now), timeZone); this.events = await this.graphService.getCalendarView( weekStart.toISOString(), weekEnd.toISOString(), this.authService.user?.timeZone ?? 'UTC'); // Temporary to display raw results this.alertsService.addSuccess('Events from Graph', JSON.stringify(events, null, 2)); } }
Damit wird derzeit nur das Array von Ereignissen in JSON auf der Seite gerendert. Speichern Sie die Änderungen, und starten Sie die App neu. Melden Sie sich an, und klicken Sie auf den Kalenderlink 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 die CalendarComponent
Komponente aktualisieren, um die Ereignisse auf benutzerfreundlichere Weise anzuzeigen.
Entfernen Sie den temporären Code, der eine Warnung aus der
ngOnInit
Funktion hinzufügt. Die aktualisierte Funktion sollte wie folgt aussehen.ngOnInit() { // Convert the user's timezone to IANA format const ianaName = findIana(this.authService.user?.timeZone ?? 'UTC'); const timeZone = ianaName![0].valueOf() || this.authService.user?.timeZone || 'UTC'; // Get midnight on the start of the current week in the user's timezone, // but in UTC. For example, for Pacific Standard Time, the time value would be // 07:00:00Z var startOfWeek = moment.tz(timeZone).startOf('week').utc(); var endOfWeek = moment(startOfWeek).add(7, 'day'); this.graphService.getCalendarView( startOfWeek.format(), endOfWeek.format(), this.authService.user?.timeZone ?? 'UTC') .then((events) => { this.events = events; }); }
Fügen Sie der
CalendarComponent
Klasse eine Funktion hinzu, um einDateTimeTimeZone
Objekt in eine ISO-Zeichenfolge zu formatieren.formatDateTimeTimeZone(dateTime: MicrosoftGraph.DateTimeTimeZone | undefined | null): string { if (dateTime == undefined || dateTime == null) { return ''; } try { // Pass UTC for the time zone because the value // is already adjusted to the user's time zone return moment.tz(dateTime.dateTime, 'UTC').format(); } catch(error) { this.alertsService.addError('DateTimeTimeZone conversion error', JSON.stringify(error)); return ''; } }
Öffnen Sie ./src/app/calendar/calendar.component.html , und ersetzen Sie den Inhalt durch Folgendes.
<h1>Calendar</h1> <a class="btn btn-light btn-sm mb-3" routerLink="/newevent">New event</a> <table class="table"> <thead> <th scope="col">Organizer</th> <th scope="col">Subject</th> <th scope="col">Start</th> <th scope="col">End</th> </thead> <tbody> <tr *ngFor="let event of events"> <td>{{event.organizer?.emailAddress?.name}}</td> <td>{{event.subject}}</td> <!-- Use 'UTC' in the pipe to date so Angular will not convert the already converted time to local time. See https://angular.io/api/common/DatePipe --> <td>{{formatDateTimeTimeZone(event.start) | date:'short' : 'UTC' }}</td> <td>{{formatDateTimeTimeZone(event.end) | date: 'short' : 'UTC' }}</td> </tr> </tbody> </table>
Dadurch wird die Ereignissammlung durchlaufen und für jedes Ereignis eine Tabellenzeile hinzugefügt. Speichern Sie die Änderungen, und starten Sie die App neu. Klicken Sie auf den Kalenderlink , und 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.
Öffnen Sie ./src/app/graph.service.ts , und fügen Sie der Klasse die
GraphService
folgende Funktion hinzu.async addEventToCalendar(newEvent: MicrosoftGraph.Event): Promise<void> { try { // POST /me/events await this.graphClient .api('/me/events') .post(newEvent); } catch (error) { throw Error(JSON.stringify(error, null, 2)); } }
Erstellen eines neuen Ereignisformulars
Erstellen Sie eine Angular Komponente, um ein Formular anzuzeigen und diese neue Funktion aufzurufen. Führen Sie den folgenden Befehl in Der CLI aus.
ng generate component new-event
Fügen Sie nach Abschluss des Befehls die Komponente dem
routes
Array in "./src/app/app-routing.module.ts" hinzu.import { NewEventComponent } from './new-event/new-event.component'; const routes: Routes = [ { path: '', component: HomeComponent }, { path: 'calendar', component: CalendarComponent }, { path: 'newevent', component: NewEventComponent }, ];
Erstellen Sie eine neue Datei im Verzeichnis "./src/app/new-event " mit dem Namen "new-event.ts" , und fügen Sie den folgenden Code hinzu.
import * as MicrosoftGraph from '@microsoft/microsoft-graph-types'; // Model for the new event form export class NewEvent { subject?: string; attendees?: string; start?: string; end?: string; body?: string; // Generate a MicrosoftGraph.Event from the model getGraphEvent(timeZone: string): MicrosoftGraph.Event { const graphEvent: MicrosoftGraph.Event = { subject: this.subject, start: { dateTime: this.start, timeZone: timeZone }, end: { dateTime: this.end, timeZone: timeZone } }; // If there are attendees, convert to array // and add them if (this.attendees && this.attendees.length > 0) { graphEvent.attendees = []; const emails = this.attendees.split(';'); emails.forEach(email => { graphEvent.attendees?.push({ type: 'required', emailAddress: { address: email } }); }); } // If there is a body, add it as plain text if (this.body && this.body.length > 0) { graphEvent.body = { contentType: 'text', content: this.body }; } return graphEvent; } }
Diese Klasse dient als Modell für das neue Ereignisformular.
Öffnen Sie ./src/app/new-event/new-event.component.ts , und ersetzen Sie den Inhalt durch den folgenden Code.
import { Component, OnInit } from '@angular/core'; import { AuthService } from '../auth.service'; import { GraphService } from '../graph.service'; import { AlertsService } from '../alerts.service'; import { NewEvent } from './new-event'; @Component({ selector: 'app-new-event', templateUrl: './new-event.component.html', styleUrls: ['./new-event.component.css'] }) export class NewEventComponent implements OnInit { model = new NewEvent(); constructor( private authService: AuthService, private graphService: GraphService, private alertsService: AlertsService) { } ngOnInit(): void { } onSubmit(): void { const timeZone = this.authService.user?.timeZone ?? 'UTC'; const graphEvent = this.model.getGraphEvent(timeZone); this.graphService.addEventToCalendar(graphEvent) .then(() => { this.alertsService.addSuccess('Event created.'); }).catch(error => { this.alertsService.addError('Error creating event.', error.message); }); } }
Öffnen Sie ./src/app/new-event/new-event.component.html , und ersetzen Sie den Inhalt durch den folgenden Code.
<h1>New event</h1> <form (ngSubmit)="onSubmit()" #newEventForm="ngForm"> <div class="form-group"> <label for="subject">Subject</label> <input type="text" class="form-control" id="subject" required [(ngModel)]="model.subject" name="subject" #name="ngModel"> <div [hidden]="name.valid || name.pristine" class="alert alert-danger">Subject is required</div> </div> <div class="form-group"> <label for="attendees">Attendees</label> <input type="text" class="form-control" id="attendees" placeholder="Enter one or more email addresses (separated with a ;) to add attendees" [(ngModel)]="model.attendees" name="attendees" #name="ngModel"> </div> <div class="form-row"> <div class="col"> <div class="form-group"> <label for="start">Start</label> <input type="datetime-local" class="form-control" id="start" required [(ngModel)]="model.start" name="start" #name="ngModel"> <div [hidden]="name.valid || name.pristine" class="alert alert-danger">Start is required</div> </div> </div> <div class="col"> <div class="form-group"> <label for="end">End</label> <input type="datetime-local" class="form-control" id="end" required [(ngModel)]="model.end" name="end" #name="ngModel"> <div [hidden]="name.valid || name.pristine" class="alert alert-danger">End is required</div> </div> </div> </div> <div class="form-group"> <label for="body">Body</label> <textarea class="form-control" id="body" rows="4" [(ngModel)]="model.body" name="body" #name="ngModel"></textarea> </div> <button type="submit" class="btn btn-primary mr-2" [disabled]="!newEventForm.form.valid">Create</button> <a class="btn btn-secondary" routerLink="/calendar">Cancel</a> </form>
Speichern Sie die Änderungen, und aktualisieren Sie die App. Wählen Sie auf der Kalenderseite die Schaltfläche "Neues Ereignis " aus, und verwenden Sie dann das Formular, um ein Ereignis im Kalender des Benutzers zu erstellen.
Herzlichen Glückwunsch!
Sie haben das Lernprogramm Angular 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.