Utiliser les SDK Microsoft Graph pour traitement par lots des demandes

Le traitement par lots est un moyen de combiner plusieurs requêtes en une seule requête HTTP. Les demandes sont combinées dans une seule charge utile JSON, qui est envoyée via POST au \$batch point de terminaison. Les SDK Microsoft Graph ont un ensemble de classes pour simplifier la façon dont vous créez des charges utiles par lot et les charges utiles de réponse par lot.

Important

Pour connaître les limitations actuelles concernant le traitement par lots JSON dans Microsoft Graph, voir Problèmes connus.

Créer une demande de lot

Les SDK Microsoft Graph fournissent trois classes pour travailler avec les requêtes et réponses par lots.

  • BatchRequestStep : représente une demande unique (par GET /me exemple) dans un lot. Il permet d’affecter un identificateur unique à la demande et de spécifier les dépendances entre les demandes.
  • BatchRequestContent - Simplifie la création de la charge utile de demande de lot. Il contient plusieurs objets BatchRequestStep.
  • BatchResponseContent : simplifie l’pare-temps de la réponse à partir d’une demande de traitement par lots. Il permet d’obtenir toutes les réponses, d’obtenir une réponse spécifique par ID et d’obtenir la @odata.nextLink propriété si elle est présente.

Exemple de traitement par lots simple

Cet exemple montre comment envoyer plusieurs demandes dans un lot qui ne dépendent pas les unes des autres. Les demandes peuvent être exécutés par le service dans n’importe quel ordre. Cet exemple obtient l’utilisateur et obtient l’affichage Calendrier de l’utilisateur pour le jour actuel.

// Use the request builder to generate a regular
// request to /me
var userRequest = graphClient.Me.Request();

var today = DateTime.Now.Date;
var start = today.ToString("yyyy-MM-ddTHH:mm:ssK");
var end = today.AddDays(1).ToString("yyyy-MM-ddTHH:mm:ssK");

var queryOptions = new List<QueryOption>
{
    new QueryOption("startDateTime", start),
    new QueryOption("endDateTime", end)
};

// Use the request builder to generate a regular
// request to /me/calendarview?startDateTime="start"&endDateTime="end"
var eventsRequest = graphClient.Me.CalendarView.Request(queryOptions);

// Build the batch
var batchRequestContent = new BatchRequestContent();

// Using AddBatchRequestStep adds each request as a step
// with no specified order of execution
var userRequestId = batchRequestContent.AddBatchRequestStep(userRequest);
var eventsRequestId = batchRequestContent.AddBatchRequestStep(eventsRequest);

var returnedResponse = await graphClient.Batch.Request().PostAsync(batchRequestContent);

// De-serialize response based on known return type
try
{
    var user = await returnedResponse
        .GetResponseByIdAsync<User>(userRequestId);
    Console.WriteLine($"Hello {user.DisplayName}!");
}
catch (ServiceException ex)
{
    Console.WriteLine($"Get user failed: {ex.Error.Message}");
}

// For collections, must use the *CollectionResponse class to deserialize
// The .Value property will contain the *CollectionPage type that the Graph client
// returns from GetAsync().
try
{
    var events = await returnedResponse
        .GetResponseByIdAsync<UserCalendarViewCollectionResponse>(eventsRequestId);
    Console.WriteLine($"You have {events.Value.CurrentPage.Count} events on your calendar today.");
}
catch (ServiceException ex)
{
    Console.WriteLine($"Get calendar view failed: {ex.Error.Message}");
}

Lots avec demandes dépendantes

Cet exemple montre comment envoyer plusieurs demandes dans un lot qui dépendent les unes des autres. Les demandes sont exécutés par le service dans l’ordre spécifié par les dépendances. Cet exemple ajoute un événement avec une heure de début pendant la journée en cours au calendrier de l’utilisateur et obtient l’affichage Calendrier de l’utilisateur pour le jour actuel. Pour vous assurer que la révision du calendrier renvoyée inclut le nouvel événement créé, la demande pour l’affichage Calendrier est configurée comme dépendant de la demande d’ajout du nouvel événement. Cela garantit que la demande d’événement d’ajout s’exécutera en premier.

Notes

Si la demande d’ajout d’événement échoue, la demande d’affichage Obtenir le calendrier échoue avec une 424 Failed Dependency erreur.

var today = DateTime.Now.Date;

var newEvent = new Event
{
    Subject = "File end-of-day report",
    Start = new DateTimeTimeZone
    {
        // 5:00 PM
        DateTime = today.AddHours(17).ToString("yyyy-MM-ddTHH:mm:ss"),
        TimeZone = TimeZoneInfo.Local.StandardName
    },
    End = new DateTimeTimeZone
    {
        // 5:30 PM
        DateTime = today.AddHours(17).AddMinutes(30).ToString("yyyy-MM-ddTHH:mm:ss"),
        TimeZone = TimeZoneInfo.Local.StandardName
    }
};

// POST requests are handled a bit differently
// The SDK request builders generate GET requests, so
// you must get the HttpRequestMessage and convert to a POST
var jsonEvent = graphClient.HttpProvider.Serializer.SerializeAsJsonContent(newEvent);

var addEventRequest = graphClient.Me.Events.Request().GetHttpRequestMessage();
addEventRequest.Method = HttpMethod.Post;
addEventRequest.Content = jsonEvent;

var start = today.ToString("yyyy-MM-ddTHH:mm:ssK");
var end = today.AddDays(1).ToString("yyyy-MM-ddTHH:mm:ssK");

var queryOptions = new List<QueryOption>
{
    new QueryOption("startDateTime", start),
    new QueryOption("endDateTime", end)
};

// Use the request builder to generate a regular
// request to /me/calendarview?startDateTime="start"&endDateTime="end"
var calendarViewRequest = graphClient.Me.CalendarView.Request(queryOptions);

// Build the batch
var batchRequestContent = new BatchRequestContent();

// Force the requests to execute in order, so that the request for
// today's events will include the new event created.

// First request, no dependency
var addEventRequestId = batchRequestContent.AddBatchRequestStep(addEventRequest);

// Second request, depends on addEventRequestId
var eventsRequestId = Guid.NewGuid().ToString();
batchRequestContent.AddBatchRequestStep(new BatchRequestStep(
    eventsRequestId,
    calendarViewRequest.GetHttpRequestMessage(),
    new List<string> { addEventRequestId }
));

var returnedResponse = await graphClient.Batch.Request().PostAsync(batchRequestContent);

// De-serialize response based on known return type
try
{
    var createdEvent = await returnedResponse
        .GetResponseByIdAsync<Event>(addEventRequestId);
    Console.WriteLine($"New event created with ID: {createdEvent.Id}");
}
catch (ServiceException ex)
{
    Console.WriteLine($"Add event failed: {ex.Error.Message}");
}

// For collections, must use the *CollectionResponse class to deserialize
// The .Value property will contain the *CollectionPage type that the Graph client
// returns from GetAsync().
try
{
    var events = await returnedResponse
        .GetResponseByIdAsync<UserCalendarViewCollectionResponse>(eventsRequestId);
    Console.WriteLine($"You have {events.Value.CurrentPage.Count} events on your calendar today.");
}
catch (ServiceException ex)
{
    Console.WriteLine($"Get calendar view failed: {ex.Error.Message}");
}

Mise en œuvre du traitement par lots à l’aide de BatchRequestContent, BatchRequestStep et HttpRequestMessage

L’exemple suivant montre comment utiliser et envoyer plusieurs demandes dans un lot et comment gérer la limite de BatchRequestContent 20 demandes d’API BatchRequestStep microsoft HttpRequestMessage Graph. Cet exemple crée des liens de réunion à l’aide onlineMeetings/createOrGet du point de terminaison de l’ID utilisateur spécifié. Vous pouvez également utiliser cet exemple avec d’Graph points de terminaison Microsoft.

using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Graph;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

public async void GenerateBatchedMeetingLink(List<ItemCollections> meetingLinksToBeGenerated)
        {            
            List<string> _joinWebUrls = new List<string>();
            //Total number of items per batch supported is 20
            int maxNoBatchItems = 20;
            try
            {
                //valid GraphAccessToken is required to execute the call
                var graphClient = GetAuthenticatedClient(GraphAccessToken);
                var events = new List<OnlineMeetingCreateOrGetRequestBody>();
                foreach (var item in meetingLinksToBeGenerated)
                {
                    var externalId = Guid.NewGuid().ToString();
                    var @event = new OnlineMeetingCreateOrGetRequestBody
                    {
                        StartDateTime = item.StartTime,
                        EndDateTime = item.EndTime,
                        Subject = "Test Meeting",
                        ExternalId = externalId,
                        
                    };
                    events.Add(@event);
                }
                // if the requests are more than 20 limit, we need to create multiple batches of the BatchRequestContent
                List<BatchRequestContent> batches = new List<BatchRequestContent>();
                var batchRequestContent = new BatchRequestContent();
                foreach (OnlineMeetingCreateOrGetRequestBody e in events)
                { 
                    //create online meeting for particular user or we can use /me as well
                    var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, $"https://graph.microsoft.com/v1.0/users/{userID}/onlineMeetings/createOrGet")
                    {
                        Content = new StringContent(JsonConvert.SerializeObject(e), Encoding.UTF8, "application/json")
                    };
                    BatchRequestStep requestStep = new BatchRequestStep(events.IndexOf(e).ToString(), httpRequestMessage, null);
                    batchRequestContent.AddBatchRequestStep(requestStep);
                    if (events.IndexOf(e) > 0 && ((events.IndexOf(e) + 1) % maxNoBatchItems == 0))
                    {
                        batches.Add(batchRequestContent);
                        batchRequestContent = new BatchRequestContent();
                    }
                }
                if (batchRequestContent.BatchRequestSteps.Count < maxNoBatchItems)
                {
                    batches.Add(batchRequestContent);
                }

                if (batches.Count == 0 && batchRequestContent != null)
                {
                    batches.Add(batchRequestContent);
                }

                foreach (BatchRequestContent batch in batches)
                {
                    BatchResponseContent response = null;
                    response = await graphClient.Batch.Request().PostAsync(batch);
                    Dictionary<string, HttpResponseMessage> responses = await response.GetResponsesAsync();
                    foreach (string key in responses.Keys)
                    {
                        HttpResponseMessage httpResponse = await response.GetResponseByIdAsync(key);
                        var responseContent = await httpResponse.Content.ReadAsStringAsync();
                        JObject eventResponse = JObject.Parse(responseContent);
                        //do something below
                        Console.writeline(eventResponse["joinWebUrl"].ToString());                      
                    }                 
                }
            }
            catch (Exception ex)
            {
                Console.Writeline(ex.Message + ex.StackTrace);               
            }
        }