Microsoft Graph aufrufen

Rufen Sie Microsoft Graph aus Ihren ASP.NET Core- und OWIN-Anwendungen mithilfe von Microsoft.Identity.Web und dem Microsoft Graph SDK auf, um auf Daten und Dienste von Microsoft 365 zuzugreifen.

Grundlegendes zur Microsoft Graph Integration

Microsoft Graph bietet einen einheitlichen API-Endpunkt für den Zugriff auf Daten über Microsoft 365, Windows und Enterprise Mobility + Security hinweg. Microsoft. Identity.Web vereinfacht die Authentifizierung und den Tokenerwerb für Microsoft Graph, während das Microsoft Graph SDK eine fluent-typierte API zum Aufrufen von Graph-Endpunkten bereitstellt.

Wählen Sie Microsoft.Identity.Web.GraphServiceClient

Die folgenden Vorteile machen Microsoft.Identity.Web.GraphServiceClient zum empfohlenen Ansatz für den Aufruf des Microsoft Graph.

  • Automatische Tokenerfassung: Verarbeitet Benutzer- und App-Token nahtlos
  • Tokenzwischenspeicherung: Integriertes Zwischenspeichern für die Leistung
  • Fluent-API: Typensichere, IntelliSense-freundliche Graph-Aufrufe
  • Inkrementelle Zustimmung: Anfordern zusätzlicher Bereiche bei Bedarf
  • Mehrere Authentifizierungsschemas: Unterstützung für Web-Apps und Web-APIs
  • Sowohl v1.0 als auch Beta: Stabile und Vorschau-Endpunkte gemeinsam verwenden

Installieren Sie die erforderlichen Pakete

Installieren Sie das Microsoft Graph SDK-Integrationspaket:

dotnet add package Microsoft.Identity.Web.GraphServiceClient

Für Microsoft Graph Beta-APIs:

dotnet add package Microsoft.Identity.Web.GraphServiceClientBeta

Einrichten von ASP.NET Core

1. Konfigurieren von Diensten

Fügen Sie Ihrer Anwendung Microsoft Graph Unterstützung hinzu:

using Microsoft.Identity.Web;

var builder = WebApplication.CreateBuilder(args);

// Add authentication (web app or web API)
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddInMemoryTokenCaches();

// Add Microsoft Graph support
builder.Services.AddMicrosoftGraph();

builder.Services.AddControllersWithViews();

var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();

2. Konfigurieren von appsettings.json

Konfigurieren von Graph-Optionen in Ihrer Konfigurationsdatei:

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "TenantId": "your-tenant-id",
    "ClientId": "your-client-id",
    "ClientSecret": "your-client-secret",
    "CallbackPath": "/signin-oidc"
  },
  "DownstreamApis": {
    "MicrosoftGraph": {
      "BaseUrl": "https://graph.microsoft.com/v1.0",
      "Scopes": ["User.Read", "User.ReadBasic.All"]
    }
  }
}

Konfiguration mit Code:

builder.Services.AddMicrosoftGraph(options =>
{
    builder.Configuration.GetSection("DownstreamApis:MicrosoftGraph").Bind(options);
});

Oder konfigurieren Sie direkt im Code:

builder.Services.AddMicrosoftGraph();
builder.Services.Configure<MicrosoftGraphOptions>(options =>
{
    options.BaseUrl = "https://graph.microsoft.com/v1.0";
    options.Scopes = new[] { "User.Read", "Mail.Read" };
});

3. Konfigurieren der nationalen Cloudunterstützung

Um Microsoft Graph in nationalen Clouds zu verwenden, geben Sie die BaseUrl in Ihrer Konfiguration an:

{
  "DownstreamApis": {
    "MicrosoftGraph": {
      "BaseUrl": "https://graph.microsoft.us/v1.0",
      "Scopes": ["User.Read"]
    }
  }
}

Informationen zu Endpunkt-URLs finden Sie unter Microsoft Graph deployments.

Verwenden von GraphServiceClient

Einfügen von GraphServiceClient

Einfügen GraphServiceClient aus dem Konstruktor:

using Microsoft.Graph;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

[Authorize]
public class ProfileController : Controller
{
    private readonly GraphServiceClient _graphClient;
    
    public ProfileController(GraphServiceClient graphClient)
    {
        _graphClient = graphClient;
    }
    
    public async Task<IActionResult> Index()
    {
        // Call Microsoft Graph
        var user = await _graphClient.Me.GetAsync();
        return View(user);
    }
}

Verwenden delegierter Berechtigungen (Benutzertoken)

Rufen Sie Graph im Namen des angemeldeten Benutzers mit delegierten Berechtigungen auf.

Abrufen eines einfachen Benutzerprofils

Rufen Sie die Profilinformationen des aktuellen Benutzers aus Microsoft Graph ab.

[Authorize]
public class ProfileController : Controller
{
    private readonly GraphServiceClient _graphClient;
    
    public ProfileController(GraphServiceClient graphClient)
    {
        _graphClient = graphClient;
    }
    
    public async Task<IActionResult> Me()
    {
        // Get current user's profile
        var user = await _graphClient.Me.GetAsync();
        
        return View(new UserViewModel
        {
            DisplayName = user.DisplayName,
            Mail = user.Mail,
            JobTitle = user.JobTitle
        });
    }
}

Fordern Sie zusätzliche Bereiche dynamisch an, wenn Ihre Anwendung sie benötigt:

[Authorize]
[AuthorizeForScopes("Mail.Read")]
public class MailController : Controller
{
    private readonly GraphServiceClient _graphClient;
    
    public MailController(GraphServiceClient graphClient)
    {
        _graphClient = graphClient;
    }
    
    public async Task<IActionResult> Inbox()
    {
        try
        {
            // Request Mail.Read scope dynamically
            var messages = await _graphClient.Me.Messages
                .GetAsync(r => r.Options.WithScopes("Mail.Read"));
            
            return View(messages);
        }
        catch (MicrosoftIdentityWebChallengeUserException)
        {
            // ASP.NET Core will redirect user to consent
            // thansk to the AuthorizeForScopes attribute.
            throw;
        }
    }
}

Anwenden von Abfrageoptionen

Verwenden Von Graph SDK-Abfrageoptionen zum Filtern, Auswählen und Sortieren von Ergebnissen:

public async Task<IActionResult> UnreadMessages()
{
    var messages = await _graphClient.Me.Messages
        .GetAsync(requestConfiguration =>
        {
            requestConfiguration.QueryParameters.Filter = "isRead eq false";
            requestConfiguration.QueryParameters.Select = new[] { "subject", "from", "receivedDateTime" };
            requestConfiguration.QueryParameters.Orderby = new[] { "receivedDateTime desc" };
            requestConfiguration.QueryParameters.Top = 10;
            
            // Request specific scope
            requestConfiguration.Options.WithScopes("Mail.Read");
        });
    
    return View(messages);
}

Ergebnisse durchblättern

Behandeln Sie seitenseitige Ergebnisse aus Microsoft Graph, indem Sie die einzelnen Seiten durchlaufen:

public async Task<IActionResult> AllUsers()
{
    var allUsers = new List<User>();
    
    // Get first page
    var users = await _graphClient.Users
        .GetAsync(r => r.Options.WithScopes("User.ReadBasic.All"));
    
    // Add first page
    allUsers.AddRange(users.Value);
    
    // Iterate through remaining pages
    var pageIterator = PageIterator<User, UserCollectionResponse>
        .CreatePageIterator(
            _graphClient,
            users,
            user =>
            {
                allUsers.Add(user);
                return true; // Continue iteration
            });
    
    await pageIterator.IterateAsync();
    
    return View(allUsers);
}

Verwenden von Anwendungsberechtigungen (nur App-Token)

Aufrufen von Graph mit Anwendungsberechtigungen, wenn kein Benutzerkontext erforderlich ist.

Aufrufen von Graph mit WithAppOnly()

Verwenden Sie die WithAppOnly() Methode, um Graph-Aufrufe mit Anwendungsberechtigungen auszuführen.

[Authorize]
[ApiController]
[Route("api/[controller]")]
public class AdminController : ControllerBase
{
    private readonly GraphServiceClient _graphClient;
    
    public AdminController(GraphServiceClient graphClient)
    {
        _graphClient = graphClient;
    }
    
    [HttpGet("users/count")]
    public async Task<ActionResult<int>> GetUserCount()
    {
        // Get count using app permissions
        var count = await _graphClient.Users.Count
            .GetAsync(r => r.Options.WithAppOnly());
        
        return Ok(count);
    }
    
    [HttpGet("applications")]
    public async Task<ActionResult> GetApplications()
    {
        // List applications using app permissions
        var apps = await _graphClient.Applications
            .GetAsync(r => r.Options.WithAppOnly());
        
        return Ok(apps.Value);
    }
}

Konfigurieren von App-Berechtigungen

Geben Sie eine App-Token-Anforderung in appsettings.json an:

{
  "DownstreamApis": {
    "MicrosoftGraph": {
      "BaseUrl": "https://graph.microsoft.com/v1.0",
      "RequestAppToken": true
    }
  }
}

Die Gültigkeitsbereiche werden automatisch auf ["https://graph.microsoft.com/.default"] gesetzt.

Konfigurieren detaillierter Nur-App-Optionen

Legen Sie explizite Nur-App-Authentifizierungsoptionen im Code fest.

public async Task<IActionResult> GetApplicationsDetailed()
{
    var apps = await _graphClient.Applications
        .GetAsync(r =>
        {
            r.Options.WithAuthenticationOptions(options =>
            {
                // Request app token explicitly
                options.RequestAppToken = true;
                
                // Scopes automatically become [.default]
                // No need to specify: options.Scopes = new[] { "https://graph.microsoft.com/.default" };
            });
        });
    
    return Ok(apps);
}

Behandeln mehrerer Authentifizierungsschemas

Wenn Ihre App mehrere Authentifizierungsschemas verwendet (z. B. Web App + API), geben Sie an, welches Schema verwendet werden soll:

using Microsoft.AspNetCore.Authentication.JwtBearer;

[Authorize]
public class ApiDataController : ControllerBase
{
    private readonly GraphServiceClient _graphClient;
    
    public ApiDataController(GraphServiceClient graphClient)
    {
        _graphClient = graphClient;
    }
    
    [HttpGet("profile")]
    public async Task<ActionResult> GetProfile()
    {
        // Specify JWT Bearer scheme
        var user = await _graphClient.Me
            .GetAsync(r => r.Options
                .WithAuthenticationScheme(JwtBearerDefaults.AuthenticationScheme));
        
        return Ok(user);
    }
}

Konfigurieren detaillierter Schemaoptionen

Legen Sie das Authentifizierungsschema und die Bereiche explizit im Code fest.

public async Task<ActionResult> GetMailWithScheme()
{
    var messages = await _graphClient.Me.Messages
        .GetAsync(r =>
        {
            r.Options.WithAuthenticationOptions(options =>
            {
                // Specify authentication scheme
                options.AcquireTokenOptions.AuthenticationOptionsName = 
                    JwtBearerDefaults.AuthenticationScheme;
                
                // Specify scopes
                options.Scopes = new[] { "Mail.Read" };
            });
        });
    
    return Ok(messages);
}

Verwenden von v1.0- und Beta-Endpunkten

Registrieren und Aufrufen von Microsoft Graph v1.0 und Beta in derselben Anwendung.

1. Installieren sie beide Pakete.

dotnet add package Microsoft.Identity.Web.GraphServiceClient
dotnet add package Microsoft.Identity.Web.GraphServiceClientBeta

2. Registrieren beider Dienste

using Microsoft.Identity.Web;

builder.Services.AddMicrosoftGraph();
builder.Services.AddMicrosoftGraphBeta();

3. Verwenden Sie beide Clients.

using GraphServiceClient = Microsoft.Graph.GraphServiceClient;
using GraphBetaServiceClient = Microsoft.Graph.Beta.GraphServiceClient;

public class MyController : Controller
{
    private readonly GraphServiceClient _graphClient;
    private readonly GraphBetaServiceClient _graphBetaClient;
    
    public MyController(
        GraphServiceClient graphClient,
        GraphBetaServiceClient graphBetaClient)
    {
        _graphClient = graphClient;
        _graphBetaClient = graphBetaClient;
    }
    
    public async Task<IActionResult> GetData()
    {
        // Use stable v1.0 endpoint
        var user = await _graphClient.Me.GetAsync();
        
        // Use beta endpoint for preview features
        var profile = await _graphBetaClient.Me.Profile.GetAsync();
        
        return View(new { user, profile });
    }
}

Batchanforderungen senden

Kombinieren Sie mehrere Graph-Aufrufe in einer einzelnen HTTP-Anforderung, um die Leistung zu verbessern:

using Microsoft.Graph.Models;

public async Task<IActionResult> GetDashboard()
{
    var batchRequestContent = new BatchRequestContentCollection(_graphClient);
    
    // Add multiple requests to batch
    var userRequest = _graphClient.Me.ToGetRequestInformation();
    var messagesRequest = _graphClient.Me.Messages.ToGetRequestInformation();
    var eventsRequest = _graphClient.Me.Events.ToGetRequestInformation();
    
    var userRequestId = await batchRequestContent.AddBatchRequestStepAsync(userRequest);
    var messagesRequestId = await batchRequestContent.AddBatchRequestStepAsync(messagesRequest);
    var eventsRequestId = await batchRequestContent.AddBatchRequestStepAsync(eventsRequest);
    
    // Send batch request
    var batchResponse = await _graphClient.Batch.PostAsync(batchRequestContent);
    
    // Extract responses
    var user = await batchResponse.GetResponseByIdAsync<User>(userRequestId);
    var messages = await batchResponse.GetResponseByIdAsync<MessageCollectionResponse>(messagesRequestId);
    var events = await batchResponse.GetResponseByIdAsync<EventCollectionResponse>(eventsRequestId);
    
    return View(new DashboardViewModel 
    { 
        User = user,
        Messages = messages.Value,
        Events = events.Value
    });
}

Anwenden allgemeiner Graph-Muster

Verwenden Sie diese Muster, um häufige Microsoft Graph Vorgänge in Ihrer Anwendung auszuführen.

Manager des Benutzers abrufen

Rufen Sie den Vorgesetzten des angemeldeten Benutzers aus dem Verzeichnis ab.

public async Task<IActionResult> GetManager()
{
    var manager = await _graphClient.Me.Manager.GetAsync();
    
    // Cast to User (manager is DirectoryObject)
    if (manager is User managerUser)
    {
        return View(managerUser);
    }
    
    return NotFound("Manager not found");
}

Benutzerfoto abrufen

Laden Sie das Profilfoto des angemeldeten Benutzers als Datenstrom herunter.

public async Task<IActionResult> GetPhoto()
{
    try
    {
        var photoStream = await _graphClient.Me.Photo.Content.GetAsync();
        
        return File(photoStream, "image/jpeg");
    }
    catch (ServiceException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
    {
        return NotFound("Photo not available");
    }
}

E-Mail senden

Senden Sie eine E-Mail-Nachricht im Namen des angemeldeten Benutzers.

public async Task<IActionResult> SendEmail([FromBody] EmailRequest request)
{
    var message = new Message
    {
        Subject = request.Subject,
        Body = new ItemBody
        {
            ContentType = BodyType.Html,
            Content = request.Body
        },
        ToRecipients = new List<Recipient>
        {
            new Recipient
            {
                EmailAddress = new EmailAddress
                {
                    Address = request.ToEmail
                }
            }
        }
    };
    
    await _graphClient.Me.SendMail
        .PostAsync(new SendMailPostRequestBody
        {
            Message = message,
            SaveToSentItems = true
        },
        requestConfiguration =>
        {
            requestConfiguration.Options.WithScopes("Mail.Send");
        });
    
    return Ok("Email sent");
}

Kalenderereignis erstellen

Erstellen Sie ein neues Kalenderereignis mit Teilnehmern für den angemeldeten Benutzer.

public async Task<IActionResult> CreateEvent([FromBody] EventRequest request)
{
    var newEvent = new Event
    {
        Subject = request.Subject,
        Start = new DateTimeTimeZone
        {
            DateTime = request.StartTime.ToString("yyyy-MM-ddTHH:mm:ss"),
            TimeZone = "UTC"
        },
        End = new DateTimeTimeZone
        {
            DateTime = request.EndTime.ToString("yyyy-MM-ddTHH:mm:ss"),
            TimeZone = "UTC"
        },
        Attendees = request.Attendees.Select(email => new Attendee
        {
            EmailAddress = new EmailAddress { Address = email },
            Type = AttendeeType.Required
        }).ToList()
    };
    
    var createdEvent = await _graphClient.Me.Events
        .PostAsync(newEvent, r => r.Options.WithScopes("Calendars.ReadWrite"));
    
    return Ok(createdEvent);
}

Benutzer durchsuchen

Suchen Sie nach Benutzern im Verzeichnis anhand des Anzeigenamens oder der E-Mail-Adresse.

public async Task<IActionResult> SearchUsers(string searchTerm)
{
    var users = await _graphClient.Users
        .GetAsync(requestConfiguration =>
        {
            requestConfiguration.QueryParameters.Filter = 
                $"startswith(displayName,'{searchTerm}') or startswith(mail,'{searchTerm}')";
            requestConfiguration.QueryParameters.Select = 
                new[] { "displayName", "mail", "jobTitle" };
            requestConfiguration.QueryParameters.Top = 10;
            
            requestConfiguration.Options.WithScopes("User.ReadBasic.All");
        });
    
    return Ok(users.Value);
}

Implementieren der OWIN-Unterstützung

Konfigurieren Sie für ASP.NET Anwendungen, die OWIN verwenden, die Token-Acquirer-Factory, und registrieren Sie Microsoft Graph Dienste.

using Microsoft.Identity.Web;
using Microsoft.Identity.Web.OWIN;
using Owin;

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
      OwinTokenAcquirerFactory factory = TokenAcquirerFactory.GetDefaultInstance<OwinTokenAcquirerFactory>();
      app.AddMicrosoftIdentityWebApi(factory);
      factory.Services
        .AddMicrosoftGraph();
      factory.Build();
    }
}

2. Aufrufen der API von Controllern

Rufen Sie eine GraphServiceClient-Instanz in Ihrem Controller ab, und rufen Sie Microsoft Graph auf.

using Microsoft.Identity.Abstractions;
using Microsoft.Identity.Web;
using System.Web.Http;

[Authorize]
public class DataController : ApiController
{
    public DataController()
    {
    }

    public async Task<IHttpActionResult> GetMyProfile()
    {
        GraphServiceClient graphServiceClient = this.GetGraphServiceClient();
        var me = await graphServiceClient.Me.GetAsync();
        return Ok(me);
    }
}

Migrieren sie von Microsoft. Identity.Web.MicrosoftGraph 2.x

Wenn Sie vom älteren Microsoft.Identity.Web.MicrosoftGraph-Paket (SDK 4.x) migrieren, überarbeiten Sie die folgenden wesentlichen Änderungen:

1. Entfernen Des alten Pakets und Hinzufügen eines neuen Pakets

dotnet remove package Microsoft.Identity.Web.MicrosoftGraph
dotnet add package Microsoft.Identity.Web.GraphServiceClient

2. Aktualisieren der Methodenaufrufe

Die .Request() Methode wurde in SDK 5.x entfernt:

Before (SDK 4.x):

var user = await _graphClient.Me.Request().GetAsync();

var messages = await _graphClient.Me.Messages
    .Request()
    .WithScopes("Mail.Read")
    .GetAsync();

After (SDK 5.x):

var user = await _graphClient.Me.GetAsync();

var messages = await _graphClient.Me.Messages
    .GetAsync(r => r.Options.WithScopes("Mail.Read"));

3. Aktualisieren von WithScopes()-Speicherort

Before:

var users = await _graphClient.Users
    .Request()
    .WithScopes("User.Read.All")
    .GetAsync();

After:

var users = await _graphClient.Users
    .GetAsync(r => r.Options.WithScopes("User.Read.All"));

4. Aktualisieren von WithAppOnly()-Speicherort

Before:

var apps = await _graphClient.Applications
    .Request()
    .WithAppOnly()
    .GetAsync();

After:

var apps = await _graphClient.Applications
    .GetAsync(r => r.Options.WithAppOnly());

5. Aktualisieren Sie die WithAuthenticationScheme()-Ort

Before:

var user = await _graphClient.Me
    .Request()
    .WithAuthenticationScheme(JwtBearerDefaults.AuthenticationScheme)
    .GetAsync();

After:

var user = await _graphClient.Me
    .GetAsync(r => r.Options
        .WithAuthenticationScheme(JwtBearerDefaults.AuthenticationScheme));

Vollständige Migrationsdetails finden Sie unter Microsoft Graph .NET SDK v5 changelog.

Fehler behandeln

Umgang mit ServiceException

Fangen Sie ODataError und MicrosoftIdentityWebChallengeUserException ab, um Graph-API-Fehler elegant zu beheben.

using Microsoft.Graph.Models.ODataErrors;

public async Task<IActionResult> GetData()
{
    try
    {
        var user = await _graphClient.Me.GetAsync();
        return Ok(user);
    }
    catch (ODataError ex) when (ex.ResponseStatusCode == 404)
    {
        return NotFound("Resource not found");
    }
    catch (ODataError ex) when (ex.ResponseStatusCode == 403)
    {
        return Forbid("Insufficient permissions");
    }
    catch (MicrosoftIdentityWebChallengeUserException)
    {
        // User needs to consent
        throw;
    }
    catch (Exception ex)
    {
        _logger.LogError(ex, "Graph API call failed");
        return StatusCode(500, "An error occurred");
    }
}

Bewährte Methoden befolgen

1. Mindestbereiche anfordern

Nur Anforderungsbereiche, die Sie benötigen:

//  Bad: Requesting too many scopes
options.Scopes = new[] { "User.Read", "Mail.ReadWrite", "Calendars.ReadWrite", "Files.ReadWrite.All" };

//  Good: Request only what you need
options.Scopes = new[] { "User.Read" };

Fordern Sie nur bei Bedarf zusätzliche Bereiche an:

// Sign-in: Only User.Read
// Later, when accessing mail:
var messages = await _graphClient.Me.Messages
    .GetAsync(r => r.Options.WithScopes("Mail.Read"));

3. Cache für GraphServiceClient

GraphServiceClient ist sicher, um wiederverwendet zu werden. Registrieren Sie sich als Singleton oder injizieren Sie aus DI.

4. Verwenden Sie "Select", um die Antwortgröße zu verringern.

//  Bad: Getting all properties
var users = await _graphClient.Users.GetAsync();

//  Good: Select only needed properties
var users = await _graphClient.Users
    .GetAsync(r => r.QueryParameters.Select = 
        new[] { "displayName", "mail", "id" });

Häufige Probleme beheben

Auflösen von "Unzureichende Berechtigungen zum Abschließen des Vorgangs"

Ursache: Die App verfügt nicht über erforderliche Graph-Berechtigungen.

Lösung:

  • Hinzufügen erforderlicher API-Berechtigungen in der App-Registrierung
  • Administratorzustimmung für App-Berechtigungen erforderlich
  • Für delegierte Berechtigungen erforderliche Benutzergenehmigung

Auflösen von "AADSTS65001: Der Benutzer oder Administrator hat nicht zugestimmt"

Ursache: Der Benutzer hat den angeforderten Bereichen nicht zugestimmt.

Lösung: Verwenden Sie inkrementelles Einverständnis mit .WithScopes(), um den Zustimmungsfluss auszulösen.

Beheben von Foto 404-Fehlern

Ursache: Der Benutzer hat kein Profilfoto.

Lösung: Behandeln Sie 404 ordnungsgemäß und stellen Sie standardmäßigen Avatar bereit.

Beheben von Batchanforderungsfehlern

Ursache: Einzelne Anforderungen im Batch können unabhängig voneinander fehlschlagen.

Lösung: Überprüfen Sie jede Antwort im Batch auf Fehler:

var userResponse = await batchResponse.GetResponseByIdAsync<User>(userRequestId);
if (userResponse == null)
{
    // Handle individual request failure
}

Nächste Schritte: Erfahren Sie mehr über Calling Azure SDKs oder custom APIs.