Usar os SDKs do Microsoft Graph para solicitações em lote

O envio em lote é uma maneira de combinar várias solicitações em uma única solicitação HTTP. As solicitações são combinadas em uma única carga JSON, que é enviada via POST para o \$batch endpoint. Os SDKs do Microsoft Graph têm um conjunto de classes para simplificar a forma como você cria conteúdos em lote e analisa os conteúdos de resposta em lote.

Importante

Para obter as limitações atuais com o envio em lote JSON no Microsoft Graph, consulte Problemas conhecidos.

Criar uma solicitação em lote

Os SDKs do Microsoft Graph fornecem três classes para trabalhar com solicitações e respostas em lote.

  • BatchRequestStep - Representa uma única solicitação (como GET /me) em um lote. Ele permite atribuir um identificador exclusivo à solicitação e especificar dependências entre as solicitações.
  • BatchRequestContent - Simplifica a criação do conteúdo da solicitação em lote. Ele contém vários objetos BatchRequestStep .
  • BatchResponseContent - Simplifica a análise da resposta de uma solicitação em lote. Ele permite que você obtenha todas as respostas, obtenha uma resposta específica por ID e obtenha a @odata.nextLink propriedade, se presente.

Envio em lote automático para limites de solicitação

O SDK do Microsoft Graph lida automaticamente com solicitações em lote em relação ao limite de 20 solicitações por lote. Isso significa que, se o código exceder esse limite, o SDK dividirá as solicitações em lotes separados nos bastidores. Isso garante que cada lote esteja em conformidade com a limitação. Você não precisa mais implementar manualmente a lógica para lidar com esse limite de envio em lote, o que torna seu código mais limpo e fácil de gerenciar.

Exemplo de envio em lote simples

Este exemplo mostra como enviar várias solicitações em um lote que não dependem umas das outras. O serviço pode executar as solicitações em qualquer ordem. Este exemplo obtém o usuário e o modo de exibição de calendário do usuário para o dia atual.

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

var today = DateTime.Now.Date;

// Use the request builder to generate a regular
// request to /me/calendarview?startDateTime="start"&endDateTime="end"
var eventsRequest = graphClient.Me.CalendarView
    .ToGetRequestInformation(requestConfiguration =>
        {
            requestConfiguration.QueryParameters.StartDateTime =
                today.ToString("yyyy-MM-ddTHH:mm:ssK");
            requestConfiguration.QueryParameters.EndDateTime =
                today.AddDays(1).ToString("yyyy-MM-ddTHH:mm:ssK");
        });

// Build the batch
var batchRequestContent = new BatchRequestContentCollection(graphClient);

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

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

// De-serialize response based on known return type
try
{
    var user = await returnedResponse
        .GetResponseByIdAsync<User>(userRequestId);
    Console.WriteLine($"Hello {user.DisplayName}!");
}
catch (Exception ex)
{
    Console.WriteLine($"Get user failed: {ex.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<EventCollectionResponse>(eventsRequestId);
    Console.WriteLine(
        $"You have {events.Value?.Count} events on your calendar today.");
}
catch (Exception ex)
{
    Console.WriteLine($"Get calendar view failed: {ex.Message}");
}

Lotes com solicitações dependentes

Este exemplo mostra como enviar várias solicitações em um lote que dependem umas das outras. O serviço executa a solicitação na ordem especificada pelas dependências. Este exemplo adiciona um evento com uma hora de início durante o dia atual ao calendário do usuário e obtém o modo de exibição de calendário do usuário para o dia atual. Para garantir que a revisão de calendário retornada inclua o novo evento criado, a solicitação para o modo de exibição de calendário é configurada como dependente da solicitação para adicionar o novo evento. Isso garante que a solicitação adicionar evento seja executada primeiro.

Observação

Se a solicitação adicionar evento falhar, a solicitação obter exibição de calendário falhará com um 424 Failed Dependency erro.

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

// Use the request builder to generate a regular
// POST request to /me/events
var addEventRequest = graphClient.Me.Events
    .ToPostRequestInformation(newEvent);

// Use the request builder to generate a regular
// request to /me/calendarview?startDateTime="start"&endDateTime="end"
var calendarViewRequest = graphClient.Me.CalendarView.ToGetRequestInformation(
    requestConfiguration =>
    {
        requestConfiguration.QueryParameters.StartDateTime =
            today.ToString("yyyy-MM-ddTHH:mm:ssK");
        requestConfiguration.QueryParameters.EndDateTime =
            today.AddDays(1).ToString("yyyy-MM-ddTHH:mm:ssK");
    });

// Build the batch
var batchRequestContent = new BatchRequestContentCollection(graphClient);

// 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 = await batchRequestContent
    .AddBatchRequestStepAsync(addEventRequest);

// Second request, depends on addEventRequestId
var eventsRequestId = Guid.NewGuid().ToString();
var eventsRequestMessage = await graphClient.RequestAdapter
    .ConvertToNativeRequestAsync<HttpRequestMessage>(calendarViewRequest);
batchRequestContent.AddBatchRequestStep(new BatchRequestStep(
    eventsRequestId,
    eventsRequestMessage,
    [addEventRequestId]));

var returnedResponse = await graphClient.Batch.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 (Exception ex)
{
    Console.WriteLine($"Add event failed: {ex.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<EventCollectionResponse>(eventsRequestId);
    Console.WriteLine(
        $"You have {events.Value?.Count} events on your calendar today.");
}
catch (Exception ex)
{
    Console.WriteLine($"Get calendar view failed: {ex.Message}");
}