Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Lesedauer 6 Min.

Kalenderdaten mit Microsoft Graph

Eine .NET-App meldet Benutzer an, lädt eine Kalenderwoche und bereitet Outlook-Termine für die Anzeige auf.
© EMGenie

Kalenderfunktionen gehören zu den naheliegendsten Einsatzfeldern von Microsoft Graph. Schon mit wenigen Aufrufen kann eine .NET-Anwendung Termine aus Microsoft 365 lesen, zeitlich eingrenzen und in einer eigenen Oberfläche darstellen. Das Beispiel zeigt den vollständigen Weg von der Anmeldung bis zur Wochenansicht und ergänzt damit den zugehörigen Leitartikel „Connected Apps mit .NET“ unter [1].

Wer Kalenderdaten eines Benutzers lesen will, braucht zunächst einen authentifizierten Zugriff auf Microsoft Graph. Für eine Desktop- oder Client-Anwendung ist ein delegierter Zugriff naheliegend: Der Benutzer meldet sich mit seinem Microsoft-Konto an, die Anwendung erhält ein Zugriffstoken und arbeitet anschließend in dessen Kontext. Das Beispiel verwendet dafür die Microsoft Authentication Library (MSAL) und das Microsoft-Graph-SDK für .NET. In der App-Registrierung in Microsoft Entra ID werden die Client-ID, ein geeigneter Redirect-URI und die benötigten delegierten Berechtigungen hinterlegt (Bild 1).

Microsoft Entra Admin Center (Bild 1)

Microsoft Entra Admin Center (Bild 1)

© Autor

Für die Anzeige (lesen) reichen im Beispiel die Scopes User.Read und Calendars.Read. Schreibrechte sind nicht erforderlich. Das ist mehr als eine Formalität: Kalender enthalten häufig sensible Informationen, deshalb sollte eine Anwendung nicht vorsorglich Calendars.ReadWrite anfordern, wenn sie Termine nur lesen und darstellen soll. Für einen öffentlichen Client wird kein Client Secret im Programm hinterlegt.

Der Kalender-Service des Beispiels kapselt Authentifizierung und Graph-Zugriff. Die Instanz der Microsoft-Authentifizierungsbibliothek (MSAL) wird anhand von Client-ID, Tenant und Redirect-URI erzeugt. Anschließend erhält der GraphServiceClient einen Authentifizierungsprovider, der vor jedem Request ein gültiges Access Token liefert. So bleibt die restliche Anwendung frei von Token- und HTTP-Details (siehe Listing 1 und Listing 2).

Listing 1: Graph-Client und Authentifizierungsprovider initialisieren
private static readonly string[] Scopes = ["User.Read", "Calendars.Read"];
{
   ...
   _pca = PublicClientApplicationBuilder.Create(clientId)
    .WithAuthority(AzureCloudInstance.AzurePublic, tenant)
    .WithRedirectUri("http://localhost").Build();
    var provider = new BaseBearerTokenAuthenticationProvider(
        new MsalAccessTokenProvider(this));
    _graphClient = new GraphServiceClient(provider);
    ...
} 
Listing 2: Interaktive Anmeldung nur bei Bedarf
public async Task LoginAsync(CancellationToken ct = default)
{
    _authResult = await AcquireTokenSilentFromCacheAsync(ct);
    if (_authResult is not null)
        return;

    _authResult = await _pca
        .AcquireTokenInteractive(Scopes)
        .WithPrompt(Prompt.SelectAccount)
        .WithUseEmbeddedWebView(false)
        .ExecuteAsync(ct);
}
 

Eine Kalenderwoche abrufen

Nach der Anmeldung ist die zentrale Frage nicht „Welche Termine gibt es?“, sondern meist: „Welche Termine liegen in dem Zeitraum, den die Oberfläche gerade zeigt?“ Genau dafür eignet sich calendarView. Der Endpunkt liefert die Kalenderereignisse innerhalb eines definierten Zeitraums und berücksichtigt dabei auch die konkreten Vorkommen von Terminserien.

Im Beispiel aus Listing 3 wird der gewünschte Zeitraum außerhalb des eigentlichen Graph-Service bestimmt. Die Methode GetCalendarEventsAsync erhält mit from und to zwei DateTimeOffset-Werte, die den Anfang und das Ende des anzuzeigenden Zeitraums beschreiben. Der Service übernimmt die Aufgabe, die zu diesem Zeitraum gehörenden Kalenderdaten aus Microsoft Graph abzurufen.

Listing 3: Termine eines definierten Zeitraums mit calendarView laden
public async Task<IReadOnlyList<OutlookCalendarEvent>> 
    GetCalendarEventsAsync(DateTimeOffset from,
                               DateTimeOffset to,
                               CancellationToken ct = default)
{
    var page = await _graphClient.Me.CalendarView.GetAsync(cfg =>
    {
        cfg.QueryParameters.StartDateTime = from.ToString("o");
        cfg.QueryParameters.EndDateTime = to.ToString("o");
        cfg.QueryParameters.Select =
            ["subject", "start", "end", "location"];
        cfg.QueryParameters.Top = 50;
    }, ct);
    return page?.Value?.Select(ev => new OutlookCalendarEvent(
        ev.Subject ?? "",
        ev.Start?.DateTime ?? "",
        ev.End?.DateTime ?? "",
        ev.Location?.DisplayName ?? "",
        ev.Start?.TimeZone ?? "",
        ev.End?.TimeZone ?? ""))
        .ToList() ?? [];
} 

Die beiden Zeitgrenzen werden mit StartDateTime und EndDateTime an calendarView übergeben. Das SDK ruft anschließend den Kalender des angemeldeten Benutzers über Me.CalendarView ab. Mit Select beschränkt die Anwendung die Antwort auf die für die Wochenansicht tatsächlich benötigten Eigenschaften: Betreff, Start, Ende und Ort. Werden später beispielsweise Organisator, Teilnehmer, Web-Link oder Informationen zu einem Online-Meeting benötigt, können weitere Eigenschaften ergänzt werden.

Ein Graph-Ereignis liefert Start und Ende nicht nur als Datums- und Zeitwert, sondern zusätzlich mit einer Zeitzonenangabe. Diese Information sollte bei der Verarbeitung berücksichtigt werden. Das Beispiel übernimmt daher neben DateTime auch TimeZone in das eigene Datenmodell. Erst bei der Aufbereitung für die Anzeige werden die Werte anhand der gelieferten Zeitzone interpretiert und in die lokale Zeitzone des Systems umgerechnet. Dadurch lassen sich beispielsweise auch Termine korrekt darstellen, die in einer anderen Zeitzone angelegt wurden.

Im Beispiel wird die Anzahl der zurückgegebenen Einträge mit Top = 50 begrenzt. Das hält die Abfrage für eine normale Wochenansicht kompakt. In produktiven Anwendungen sollte zusätzlich berücksichtigt werden, dass Microsoft Graph Ergebnisse seitenweise zurückgeben kann. Enthält der abgefragte Zeitraum mehr Ereignisse, als in einer Antwort geliefert werden, muss auch die nächste Ergebnisseite verarbeitet werden. Das ist insbesondere bei gemeinsam genutzten oder stark belegten Kalendern relevant.

Vom Event zur Wochenansicht

Die Antwort von Microsoft Graph liefert zunächst Kalenderdaten, aber noch keine fertige Darstellung für eine Wochenansicht. Zwischen API und Oberfläche ist daher eine kleine Aufbereitungsschicht sinnvoll. Sie legt fest, welcher Zeitraum angezeigt werden soll, vereinheitlicht Datums- und Zeitangaben, ordnet die Termine den einzelnen Wochentagen zu und erzeugt daraus ein für die Darstellung geeignetes Datenmodell.

Für eine klassische Wochenansicht bietet es sich an, den Zeitraum von Montag bis Sonntag zu bestimmen und genau diesen Bereich über calendarView abzufragen (Listing 4). Beim Wechsel auf die vorherige oder nächste Woche wird lediglich das Bezugsdatum um sieben Tage verschoben.

Listing 4: Kalenderdaten einer Woche laden und für die Anzeige vorbereiten
public async Task<IReadOnlyList<CalendarDisplayItem>>LoadWeekAsync(
    DateTime referenceDate, CancellationToken ct = default)
{
    var monday = GetStartOfWeek(referenceDate);
    var sunday = monday.AddDays(6);
    var from = new DateTimeOffset(
        monday.Year, monday.Month, monday.Day,
        0, 0, 0,
        TimeZoneInfo.Local.GetUtcOffset(monday));
    var to = new DateTimeOffset(
        sunday.Year, sunday.Month, sunday.Day,
        23, 59, 59,
        TimeZoneInfo.Local.GetUtcOffset(sunday));
    var events = await _calendarService
        .GetCalendarEventsAsync(from, to, ct);
    return events
        .Select(ToDisplayItem)
        .OrderBy(item => item.StartLocal)
        .ToList();
} 

Die Methode erhält lediglich ein Bezugsdatum. Daraus werden Anfang und Ende der betreffenden Woche ermittelt und an den Calendar-Service übergeben. Die zurückgegebenen Graph-Ereignisse werden anschließend nicht direkt an die Benutzeroberfläche weitergereicht. Stattdessen entsteht für jedes Ereignis ein eigenes, bewusst einfach gehaltenes Anzeigemodell. Ein solches Modell kann, wie in Listing 5 gezeigt, beispielsweise die lokale Startzeit, einen bereits formatierten Zeitraum, den Betreff und den Ort enthalten.

Listing 5: Datenmodell für Kalendereintrag
public sealed class CalendarDisplayItem
{
    public DateTime StartLocal { get; init; }
    public DateTime EndLocal { get; init; }
    public string TimeText { get; init; } = "";
    public string Title { get; init; } = "";
    public string Description { get; init; } = "";
} 

Bei der Konvertierung werden zunächst die von Microsoft Graph gelieferten Start- und Endwerte einschließlich ihrer Zeitzonen interpretiert. Danach lassen sich die Werte in die lokale Zeitzone überführen und bereits für die spätere Darstellung formatieren. Aus einem Graph-Ereignis mit Betreff, Beginn, Ende und Ort entsteht beispielsweise ein CalendarDisplayItem mit TimeText im Format 09:00 - 10:30 Uhr.

Damit muss die Oberfläche weder das Graph-Datenmodell noch Besonderheiten des API kennen. Sie erhält ausschließlich Daten, die bereits für den konkreten Anwendungsfall vorbereitet sind. Gleichzeitig lässt sich die Aufbereitung unabhängig von der verwendeten UI-Technologie testen und später leicht erweitern.

Für die Darstellung als Kalenderwoche werden die Einträge anschließend nach Datum beziehungsweise Wochentag gruppiert. Das kann beispielsweise mit LINQ erfolgen, vergleiche Listing 6.

Listing 6: Auswahl bestimmter Kalendertage
var days = displayItems
    .GroupBy(item => item.StartLocal.Date)
    .ToDictionary(
        group => group.Key,
        group => group
            .OrderBy(item => item.StartLocal)
            .ToList()); 

Die Oberfläche kann damit für jeden Tag der sichtbaren Woche die zugehörigen Termine abrufen und in chronologischer Reihenfolge anzeigen. Ob daraus sieben nebeneinanderliegende Spalten, eine Tagesliste oder eine kompakte mobile Ansicht entstehen, ist für die Datenaufbereitung zunächst unerheblich.

Besondere Aufmerksamkeit verdienen mehrtägige Ereignisse. Ein Termin, der beispielsweise am Mittwoch beginnt und am Freitag endet, lässt sich nicht sinnvoll nur dem Starttag zuordnen. Für eine kompakte Wochenansicht kann das Ereignis deshalb in mehrere Anzeigeelemente zerlegt werden. Am ersten Tag erscheint die Startzeit, an den dazwischenliegenden Tagen beispielsweise der Hinweis „Ganztägig“ und am letzten Tag die Endzeit. Liegt ein Teil des Ereignisses außerhalb der aktuell dargestellten Woche, wird nur der sichtbare Abschnitt berücksichtigt.

Diese Aufbereitung ist eine Entscheidung der Anwendung und ist nicht von Microsoft Graph vorgegeben. Graph liefert Start, Ende und weitere Eigenschaften des Ereignisses. Wie daraus eine Wochen-, Monats- oder Listenansicht entsteht, entscheidet die eigene Präsentationslogik.

Ist das Datenmodell entsprechend vorbereitet, bleibt auch die eigentliche Anzeige einfach. Eine XAML-basierte Oberfläche kann beispielsweise wie in Listing 7 direkt an eine Liste vorbereiteter Termine gebunden werden.

Listing 7: Beispielhafte Darstellung vorbereiteter Termine in XAML
<CollectionView ItemsSource="{Binding Appointments}">
    <CollectionView.ItemTemplate>
        <DataTemplate>
            <VerticalStackLayout Padding="0,5">
                <Label
                    Text="{Binding TimeText}"
                    FontAttributes="Bold" />
                <Label
                    Text="{Binding Title}" />
                <Label
                    Text="{Binding Description}"
                    FontSize="12" />
            </VerticalStackLayout>
        </DataTemplate>
    </CollectionView.ItemTemplate>
</CollectionView> 

Das gleiche Prinzip funktioniert unabhängig davon, ob .NET MAUI, WinUI, WPF oder mit Blazor eine Weboberfläche zum Einsatz kommt. Entscheidend ist die Trennung der Aufgaben: Microsoft Graph liefert die Kalenderereignisse, die Anwendung normalisiert und strukturiert die Daten, und die Oberfläche kümmert sich ausschließlich um ihre Darstellung.

Für umfangreichere Kalenderansichten kann das Anzeigemodell zusätzlich Eigenschaften wie Organisator, Teilnehmer, Kategorien, Besprechungsstatus, Teams-Link oder Kennzeichnungen für ganztägige und mehrtägige Termine aufnehmen. Die Graph-Abfrage selbst muss dafür nicht grundsätzlich verändert werden. Meist genügt es, die benötigten Eigenschaften über $select zusätzlich anzufordern und bei der Aufbereitung zu berücksichtigen.

Fazit

Microsoft Graph macht aus dem Outlook-Kalender eine direkt nutzbare Datenquelle für eigene .NET-Anwendungen. Für eine Wochenansicht sind nur wenige Bausteine nötig: App-Registrierung und delegierte Anmeldung, ein GraphServiceClient, eine zeitlich begrenzte calendarView-Abfrage und eine Aufbereitung der Daten für die View, welche die Ereignisse für die Oberfläche vorbereitet.

[1] Veikko Krypczyk, Connected Apps mit .NET, dotnetpro 4/2026, Seite 36 ff.

Neueste Beiträge

KI ersetzt keine Softskills – sie deckt nur gnadenlos auf, wer keine hat - Interview
Auf der Open Stage der DWX 2026 vertrat Recruiting-Expertin Laura Rheinwald von ITech Progress in ihrem Vortrag die Meinung, dass die KI die Kommunikation zwischen Menschen verändert. Developer World wollte von ihr wissen, in welcher Weise.
23. Sep 2026
Kostenkontrolle bei KI-Coding-Agenten
Best Practices für eine ökonomisch nachhaltige Entwicklung.
8 Minuten
Connected Apps mit .NET - Graph API als Integrationsplattform
Microsoft Graph bietet .NET-Entwicklern einheitlichen Zugang zu den Daten und Diensten von Microsoft 365 – für moderne, sichere und kontextbezogene Business-Anwendungen.
17 Minuten

Das könnte Dich auch interessieren

DB API Marketplace ersetzt das Open API Portal - Deutsche Bahn
Die Deutsche Bahn entwickelt sein DB Open Data Angebot weiter. Der erste Schritt ist die Umstellung des bisherigen Open API Portals auf den neuen DB API Marketplace.
2 Minuten
30. Mai 2022
REST als Architekturstil - Representational State Transfer
Sechs grundlegende Prinzipien und drei Reifegrade.
9 Minuten
14. Aug 2023
SDK für elektronische Rechnungen - 21.06.2013, 00:00 Uhr
Derzeit laufen Bestrebungen einen einheitlichen Standard für elektronische Rechnungen zu setzen. Jetzt wurde ein erstes Windows-SDK dafür vorgestellt.
2 Minuten
21. Jun 2013
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige