Microsoft Graph

De Banane Atomic
Aller à la navigationAller à la recherche

Liens

Description

Microsoft Graph remplace Office 365 API et Azure AD Graph API.
Il réunit au sein d'une unique API toutes les données relatives aux utilisateurs.

Web-hosted resource Application ID URI
The Office 365 Unified Mail API https://outlook.office.com
The Azure AD Graph API https://graph.windows.net
Microsoft Graph https://graph.microsoft.com

Permissions

Base url https://graph.microsoft.com/v1.0
L'erreur Access is denied. Check credentials and try again. signifie qu'il manque des permissions pour l'appel de la web API.
Description Url Permissions
Profil de l'utilisateur courant /me Pas de permission nécessaire,
fonctionne même sans l'ajout de l'API Microsoft Graph dans les permissions.
Liste des profils des utilisateurs /users Access directory as the signed in user
Photo
beta
/users/<userId>/photo/$value View users' basic profile
Read all users' basic profiles
Envoyer un email POST /me/sendMail Send mail as a user
Nécessite Outlook on the web (Exchange Web Connect, Outlook Web Access OWA)
Sinon erreur Resource could not be discovered
Événements du calendrier /me/events
/users/<userId>/events
Read user calendars
Accès aux configuration InTune
beta
/me/managedDevices Read Microsoft Intune apps (DeviceManagementApps.Read.All)

Converged vs Azure AD applications

Graph ne fonctionne qu'avec des Converged apps et pas avec des AAD apps.
Les Converged apps sont a enregistrer sur apps.dev.microsoft.com

Filtres sur les requêtes

Exemples
users?$filter=givenName eq 'Nicolas' and surname eq 'XXX')
users?$filter=startswith(givenName,'Nicolas')
me/events?$filter=start/dateTime ge '2009-06-15T13:45:30'
users?$top=999
users?$select=givenName,surname
me/events?$orderby=start/dateTime
Utiliser HttpUtility.UrlEncode pour encoder le contenu du filtre.

Video REST API

URL Description
https://xxx.sharepoint.com/portals/hub/_api/VideoService/Channels Liste des channels
https://xxx.sharepoint.com/portals/hub/_api/VideoService/Channels/(guid'xxx')/Videos(guid'xxx')/ThumbnailStream Thumbnail

Microsoft.Graph client library

  • package Nuget Microsoft.Graph
Csharp.svg
var graphClient = new GraphServiceClient(
        "https://graph.microsoft.com/v1.0",
        new DelegateAuthenticationProvider(
            async (requestMessage) =>
            {
                var token = TokenGraph;
                requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", token);
                await Task.FromResult("");
            }));

// User Me
var user = await graphClient.Me.Request().GetAsync();
string userId = user.Id;

NextMeetingsForGraphSample

Csharp.svg
var start = DateTime.UtcNow.ToString("o");
var end = DateTime.UtcNow.AddDays(7).ToString("o");

var optionStart = new QueryOption("startDateTime", start);
var optionEnd = new QueryOption("endDateTime", end);

IUserCalendarViewCollectionPage calendarView = await graphService.Me.CalendarView.Request(new[] { optionStart, optionEnd }).GetAsync();

var hasMorePages = true;
var events = new List<Event>();
while (hasMorePages)
{
    foreach (var ev in calendarView.CurrentPage.ToList())
        events.Add(ev);
    hasMorePages = calendarView.NextPageRequest != null;
    if (hasMorePages)
        calendarView = await calendarView.NextPageRequest.GetAsync();
}

foreach (var ev in events) {}

WPF client

Avec un token Azure AD

MainWindows.xaml.cs
private string _clientId = "xxx";
private static string _tenant = "xxx.onmicrosoft.com";
private string _authority = $"https://login.microsoftonline.com/{_tenant}";

private string _graphResourceUrl = "https://graph.microsoft.com";
private string _resourceUrl = "https://xxx.onmicrosoft.com/xxx";

private Uri _redirectUri = new Uri("https://wpfclient");
string[] scopes = new string[] { "user.read" };

private HttpClient _httpClient = new HttpClient();
private string _token;
private string _tokenGraph;

private async void signin_Click(object sender, RoutedEventArgs e)
{
    AuthenticationContext authContext = new AuthenticationContext(_authority);
    AuthenticationResult authResult = null;

    try
    {
        authResult = await authContext.AcquireTokenAsync(_resourceUrl, _clientId, _redirectUri, new PlatformParameters(PromptBehavior.Auto));
        _token = authResult.AccessToken;
        AppendText("You signed in!");
    }
    catch (AdalException aex)
    {
        AppendText(aex.ToString());
    }
}

// get the token graph automatically if the azure AD is already in the cache
private async void tokengraph_Click(object sender, RoutedEventArgs e)
{
    AuthenticationContext authContext = new AuthenticationContext(_authority);
    AuthenticationResult authResult = null;

    try
    {
        authResult = await authContext.AcquireTokenSilentAsync(_graphResourceUrl, _clientId);
        _tokenGraph = authResult.AccessToken;
        AppendText("You got the token for the graph!");
    }
    catch (AdalException aex)
    {
        AppendText(aex.ToString());
    }
}

// use the token graph to request the graph
private async void profile_Click(object sender, RoutedEventArgs e)
{
    string url = "https://graph.microsoft.com/v1.0/me";

    if (_tokenGraph != null)
    {
        HttpResponseMessage response;
        try
        {
            var request = new HttpRequestMessage(HttpMethod.Get, url);
            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _tokenGraph);
            response = await _httpClient.SendAsync(request);
            var content = await response.Content.ReadAsStringAsync();
            AppendText(content);
        }
        catch (Exception ex)
        {
            AppendText(ex.ToString());
        }
    }
    else
    {
        AppendText("You need to get the token graph first.");
    }
}

Avec Microsoft.Identity.Client

Packages Nuget:

  • Microsoft.Identity.Client
MainWindows.xaml.cs
// config
// client ID de Converged applications.
// ne fonctionne pas avec les client ID des AAD applications
// AADSTS70001: Application is not supported for this API version.
private string _clientId = "xxx";
private static string _tenant = "xxx.onmicrosoft.com";
private string _authority = $"https://login.microsoftonline.com/{_tenant}";
// Set the scope for API call to user.read
string[] scopes = new string[] { "user.read" };

private PublicClientApplication _clientApp;
Microsoft.Identity.Client.AuthenticationResult authResult = null;
private HttpClient _httpClient = new HttpClient();

public MainWindow()
{
    InitializeComponent();
    _clientApp = new PublicClientApplication(_clientId, _authority, TokenCacheHelper.GetUserCache());
}

private async void signin_Click(object sender, RoutedEventArgs e)
{
    try
    {
        authResult = await _clientApp.AcquireTokenSilentAsync(scopes, _clientApp.Users.FirstOrDefault());
        AppendText("Signed-in using the cache.");
    }
    catch (MsalUiRequiredException ex)
    {
        try
        {
            authResult = await _clientApp.AcquireTokenAsync(scopes);
            AppendText("Signed-in successfully.");
        }
        catch (MsalException msalex)
        {
            AppendText($"Error Acquiring Token:\n{msalex}");
        }
    }
    catch (Exception ex)
    {
        AppendText($"Error Acquiring Token Silently:\n{ex}");
        return;
    }
}

private void signout_Click(object sender, RoutedEventArgs e)
{

}

private async void getProfile_Click(object sender, RoutedEventArgs e)
{
    //Set the API Endpoint to Graph 'me' endpoint
    string graphAPIEndpoint = "https://graph.microsoft.com/v1.0/me";

    if (authResult != null)
    {
        AppendText(await GetHttpContentWithToken(graphAPIEndpoint, authResult.AccessToken));
    }
    else
    {
        AppendText("You need to sign-in first.");
    }
}

/// <summary>
/// Perform an HTTP GET request to a URL using an HTTP Authorization header
/// </summary>
/// <param name="url">The URL</param>
/// <param name="token">The token</param>
/// <returns>String containing the results of the GET operation</returns>
public async Task<string> GetHttpContentWithToken(string url, string token)
{
    HttpResponseMessage response;
    try
    {
        var request = new HttpRequestMessage(HttpMethod.Get, url);
        // Add the token in Authorization header
        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
        response = await _httpClient.SendAsync(request);
        var content = await response.Content.ReadAsStringAsync();
        return content;
    }
    catch (Exception ex)
    {
        return ex.ToString();
    }
}
TokenCacheHelper.cs
static class TokenCacheHelper
{
    public static TokenCache GetUserCache()
    {
        if (usertokenCache == null)
        {
            usertokenCache = new TokenCache();
            usertokenCache.SetBeforeAccess(BeforeAccessNotification);
            usertokenCache.SetAfterAccess(AfterAccessNotification);
        }
        return usertokenCache;
    }

    static TokenCache usertokenCache;

    public static string CacheFilePath = System.Reflection.Assembly.GetExecutingAssembly().Location + "msalcache.txt";

    private static readonly object FileLock = new object();

    public static void BeforeAccessNotification(TokenCacheNotificationArgs args)
    {
        lock (FileLock)
        {
            args.TokenCache.Deserialize(File.Exists(CacheFilePath)
                ? File.ReadAllBytes(CacheFilePath)
                : null);
        }
    }

    public static void AfterAccessNotification(TokenCacheNotificationArgs args)
    {
        // if the access operation resulted in a cache update
        if (args.TokenCache.HasStateChanged)
        {
            lock (FileLock)
            {
                // reflect changes in the persistent store
                File.WriteAllBytes(CacheFilePath, args.TokenCache.Serialize());
                // once the write operation takes place restore the HasStateChanged bit to false
                args.TokenCache.HasStateChanged = false;
            }
        }
    }
}

Erreurs

Application is not supported for this API version.

  • Inscrire l'application comme converged app sur apps.dev.microsoft.com
  • Configurer l'app (redirect url)
  • Utiliser le client id de la converged app