Microsoft Graph aanroepen

Roep Microsoft Graph aan vanuit uw ASP.NET Core- en OWIN-toepassingen met behulp van Microsoft. Identity.Web en de Microsoft Graph SDK voor toegang tot Microsoft 365 gegevens en services.

Inzicht in Microsoft Graph-integratie

Microsoft Graph biedt een geïntegreerd API-eindpunt voor toegang tot gegevens in Microsoft 365, Windows en Enterprise Mobility + Security. Microsoft. Identity.Web vereenvoudigt verificatie en tokenverwerving voor Microsoft Graph, terwijl de Microsoft Graph SDK een vloeiende, getypte API biedt voor het aanroepen van Graph-eindpunten.

Kies Microsoft. Identity.Web.GraphServiceClient

De volgende voordelen maken Microsoft.Identity.Web.GraphServiceClient de aanbevolen methode voor het aanroepen van Microsoft Graph.

  • Automatische tokenverwerving: verwerkt naadloos gebruikers- en app-tokens
  • Tokencaching: ingebouwde caching voor prestaties
  • Fluent API: Type-safe en IntelliSense-vriendelijke Graph-aanroepen
  • Incrementele toestemming: aanvullende rechten op aanvraag vragen
  • Meerdere verificatieschema's: ondersteuning voor web-apps en web-API's
  • Zowel v1.0 als bèta: stabiele en preview-eindpunten samen gebruiken

De vereiste pakketten installeren

Installeer het Microsoft Graph SDK-integratiepakket:

dotnet add package Microsoft.Identity.Web.GraphServiceClient

Voor Microsoft Graph bèta-API's:

dotnet add package Microsoft.Identity.Web.GraphServiceClientBeta

ASP.NET Core instellen

1. Services configureren

Voeg Microsoft Graph ondersteuning toe aan uw toepassing:

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. Configureer appsettings.json

De configopties voor grafieken instellen in uw configuratiebestand:

{
  "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"]
    }
  }
}

Configuratie met code:

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

Of configureer rechtstreeks in 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. Nationale cloudondersteuning configureren

Als u Microsoft Graph in nationale clouds wilt gebruiken, geeft u de BaseUrl op in uw configuratie:

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

Zie Microsoft Graph-implementaties voor eindpunt-URL's.

GraphServiceClient gebruiken

GraphServiceClient injecteren

Injecteren GraphServiceClient vanuit de constructor:

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);
    }
}

Gedelegeerde machtigingen gebruiken (gebruikerstokens)

Roep Graph aan namens de aangemelde gebruiker met gedelegeerde machtigingen.

Basisgebruikersprofiel ophalen

Haal de profielgegevens van de huidige gebruiker op uit Microsoft Graph.

[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
        });
    }
}

Vraag dynamisch aanvullende bereiken aan wanneer uw toepassing deze nodig heeft:

[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;
        }
    }
}

Queryopties toepassen

Gebruik Graph SDK-queryopties om resultaten te filteren, te selecteren en te ordenen:

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);
}

Bladeren door resultaten

Behandel paginaresultaten van Microsoft Graph door elke pagina door te nemen:

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);
}

Toepassingsmachtigingen gebruiken (alleen-app-tokens)

Roep Graph aan met toepassingsmachtigingen wanneer er geen gebruikerscontext is vereist.

Grafiek aanroepen met WithAppOnly()

Gebruik de WithAppOnly() methode om Graph-aanroepen te maken met toepassingsmachtigingen.

[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);
    }
}

App-machtigingen configureren

Geef een app-tokenaanvraag op in appsettings.json:

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

De scopes worden automatisch ingesteld op ["https://graph.microsoft.com/.default"].

Gedetailleerde opties alleen voor apps configureren

Stel expliciete opties voor app-only authenticatie in binnen de code.

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);
}

Meerdere verificatieschema's hanteren

Als uw app gebruikmaakt van meerdere verificatieschema's (bijvoorbeeld web-app + API), geeft u op welk schema u wilt gebruiken:

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);
    }
}

Gedetailleerde schemaopties configureren

Stel het verificatieschema en de scopes expliciet in de code in.

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);
}

Zowel v1.0- als bèta-eindpunten gebruiken

Registreer en roep zowel Microsoft Graph v1.0 als beta aan in dezelfde toepassing.

1. Beide pakketten installeren

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

2. Beide services registreren

using Microsoft.Identity.Web;

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

3. Beide clients gebruiken

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 });
    }
}

Batchaanvragen verzenden

Combineer meerdere Graph-aanroepen in één HTTP-aanvraag om de prestaties te verbeteren:

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
    });
}

Algemene grafiekpatronen toepassen

Gebruik deze patronen om frequente Microsoft Graph bewerkingen uit te voeren in uw toepassing.

Het verkrijgen van de manager van de gebruiker

Haal de manager van de aangemelde gebruiker op uit de directory.

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");
}

Foto van gebruiker ophalen

Download de profielfoto van de aangemelde gebruiker als een stream.

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 verzenden

Verzend een e-mailbericht namens de aangemelde gebruiker.

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");
}

Agendagebeurtenis maken

Maak een nieuwe agendagebeurtenis met deelnemers voor de aangemelde gebruiker.

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);
}

Gebruikers zoeken

Zoek naar gebruikers in het directory op weergavenaam of e-mailadres.

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);
}

OWIN-ondersteuning implementeren

Voor ASP.NET toepassingen die gebruikmaken van OWIN, configureert u de token acquirer factory en registreert u Microsoft Graph services.

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. API aanroepen vanaf controllers

Haal een GraphServiceClient-exemplaar op in uw controller en roep Microsoft Graph aan.

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);
    }
}

Migreren van Microsoft. Identity.Web.MicrosoftGraph 2.x

Als u migreert van de oudere Microsoft. Identity.Web.MicrosoftGraph package (SDK 4.x), controleer de volgende belangrijke wijzigingen:

1. Oud pakket verwijderen en nieuw toevoegen

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

2. Methode-aanroepen bijwerken

De .Request() methode is verwijderd in SDK 5.x:

Vóór (SDK 4.x):

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

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

Na (SDK 5.x):

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

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

Bijwerken van WithScopes() locatie

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. Bijwerken van de locatie van WithAppOnly()

Before:

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

After:

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

5. Update locatie van WithAuthenticationScheme()

Before:

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

After:

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

Zie Microsoft Graph .NET SDK v5 changelog voor volledige migratiedetails.

Afhandeling van fouten

ServiceException verwerken

Catch ODataError en MicrosoftIdentityWebChallengeUserException om Graph API-fouten op een elegante manier af te handelen.

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");
    }
}

Best practices volgen

1. Minimale machtigingen aanvragen

Alleen aanvraagbereiken die u nodig hebt:

//  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" };

Vraag alleen extra bereiken aan wanneer dat nodig is:

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

3. Cache GraphServiceClient

GraphServiceClient is veilig om opnieuw te gebruiken. Registreer als singleton of voer in vanuit DI.

4. Selecteer deze optie om de responsgrootte te verkleinen

//  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" });

Veelvoorkomende problemen oplossen

'Onvoldoende bevoegdheden om de bewerking te voltooien' oplossen

Oorzaak: App heeft geen vereiste Graph-machtigingen.

Solution:

  • Vereiste API-machtigingen toevoegen in app-registratie
  • Beheerderstoestemming vereist voor app-machtigingen
  • Gebruikerstoestemming vereist voor gedelegeerde machtigingen

'AADSTS65001: de gebruiker of beheerder heeft geen toestemming gegeven' oplossen

Oorzaak: De gebruiker heeft geen toestemming gegeven voor de gevraagde machtigingen.

Oplossing: Gebruik incrementele toestemming om .WithScopes() toestemmingsstroom te activeren.

Foto 404-fouten oplossen

Oorzaak: Gebruiker heeft geen profielfoto.

Oplossing: 404 correct verwerken en standaard avatar bieden.

Fouten met batchaanvragen oplossen

Oorzaak: afzonderlijke aanvragen in batch kunnen onafhankelijk mislukken.

Oplossing: Controleer elk antwoord in batch op fouten:

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

Volgende stappen: Meer informatie over het aanroepen van Azure SDK's of aangepaste API's.