Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/Microsoft.Graph.Core/Requests/BatchRequestBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,26 @@ public async Task<BatchResponseContent> PostAsync(BatchRequestContent batchReque
return new BatchResponseContent(nativeResponseHandler.Value as HttpResponseMessage);
}

/// <summary>
/// Sends out the <see cref="BatchRequestContentCollection"/> using the POST method
/// </summary>
/// <param name="batchRequestContentCollection">The <see cref="BatchRequestContentCollection"/> for the request</param>
/// <param name="cancellationToken"><see cref="CancellationToken"/> to use for cancelling requests</param>
/// <returns></returns>
public async Task<BatchResponseContentCollection> PostAsync(BatchRequestContentCollection batchRequestContentCollection, CancellationToken cancellationToken = default)
{
var collection = new BatchResponseContentCollection();

var requests = batchRequestContentCollection.GetBatchRequestsForExecution();
foreach (var request in requests)
{
var response = await PostAsync(request, cancellationToken);
collection.AddResponse(request.BatchRequestSteps.Keys, response);
}

return collection;
}

/// <summary>
/// Create <see cref="RequestInformation"/> instance to post to batch endpoint
/// <param name="batchRequestContent">The <see cref="BatchRequestContent"/> for the request</param>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
namespace Microsoft.Graph
{
using Microsoft.Kiota.Abstractions;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;

/// <summary>
/// A collection of batch requests that are automatically managed.
/// </summary>
public class BatchRequestContentCollection
{
private readonly IBaseClient baseClient;
private readonly List<BatchRequestContent> batchRequests;
private BatchRequestContent currentRequest;
private bool readOnly = false;

/// <summary>
/// Constructs a new <see cref="BatchRequestContentCollection"/>.
/// </summary>
/// <param name="baseClient">The <see cref="IBaseClient"/> for making requests</param>
public BatchRequestContentCollection(IBaseClient baseClient)
{
this.baseClient = baseClient;
batchRequests = new List<BatchRequestContent>();
currentRequest = new BatchRequestContent(baseClient);
}

private void ValidateReadOnly()
{
if (readOnly)
{
throw new InvalidOperationException("Batch request collection is already executed");
}
}

private void SetupCurrentRequest()
{
ValidateReadOnly();
if (currentRequest.BatchRequestSteps.Count >= CoreConstants.BatchRequest.MaxNumberOfRequests)
{
batchRequests.Add(currentRequest);
currentRequest = new BatchRequestContent(baseClient);
}
}

/// <summary>
/// Adds a <see cref="HttpRequestMessage"/> to batch request content.
/// </summary>
/// <param name="httpRequestMessage">A <see cref="HttpRequestMessage"/> to use to build a <see cref="BatchRequestStep"/> to add.</param>
/// <returns>The requestId of the newly created <see cref="BatchRequestStep"/></returns>
public string AddBatchRequestStep(HttpRequestMessage httpRequestMessage)
{
SetupCurrentRequest();
return currentRequest.AddBatchRequestStep(httpRequestMessage);
}

/// <summary>
/// Adds a <see cref="RequestInformation"/> to batch request content
/// </summary>
/// <param name="requestInformation">A <see cref="RequestInformation"/> to use to build a <see cref="BatchRequestStep"/> to add.</param>
/// <returns>The requestId of the newly created <see cref="BatchRequestStep"/></returns>
public Task<string> AddBatchRequestStepAsync(RequestInformation requestInformation)
{
SetupCurrentRequest();
return currentRequest.AddBatchRequestStepAsync(requestInformation);
}

/// <summary>
/// Removes a <see cref="BatchRequestStep"/> from batch request content for the specified id.
/// </summary>
/// <param name="requestId">A unique batch request id to remove.</param>
/// <returns>True or false based on removal or not removal of a <see cref="BatchRequestStep"/>.</returns>
public bool RemoveBatchRequestStepWithId(string requestId)
{
ValidateReadOnly();
var removed = currentRequest.RemoveBatchRequestStepWithId(requestId);
if (!removed && batchRequests.Count > 0)
{
for (int i = 0; i < batchRequests.Count; i++)
{
removed = batchRequests[i].RemoveBatchRequestStepWithId(requestId);
if (removed)
{
return true;
}
}
}
return removed;
}

internal IEnumerable<BatchRequestContent> GetBatchRequestsForExecution()
{
readOnly = true;
if (currentRequest.BatchRequestSteps.Count > 0)
{
batchRequests.Add(currentRequest);
}

return batchRequests;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
namespace Microsoft.Graph
{
using Microsoft.Kiota.Abstractions;
using Microsoft.Kiota.Abstractions.Serialization;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;

/// <summary>
/// Handles batch request responses.
/// </summary>
public class BatchResponseContentCollection
{
private readonly List<KeyedBatchResponseContent> batchResponses;

internal BatchResponseContentCollection()
{
batchResponses = new List<KeyedBatchResponseContent>();
}

internal void AddResponse(IEnumerable<string> keys, BatchResponseContent content)
{
batchResponses.Add(new KeyedBatchResponseContent(new HashSet<string>(keys), content));
}

private BatchResponseContent GetBatchResponseContaining(string requestId)
{
return batchResponses.FirstOrDefault(b => b.Keys.Contains(requestId))?.Response;
}

/// <summary>
/// Gets a batch response as <see cref="HttpResponseMessage"/> for the specified batch request id.
/// The returned <see cref="HttpResponseMessage"/> MUST be disposed since it implements an <see cref="IDisposable"/>.
/// </summary>
/// <param name="requestId">A batch request id.</param>
/// <returns>A <see cref="HttpResponseMessage"/> response object for a batch request.</returns>
public Task<HttpResponseMessage> GetResponseByIdAsync(string requestId)
{
return GetBatchResponseContaining(requestId)?.GetResponseByIdAsync(requestId)
?? Task.FromResult<HttpResponseMessage>(null);
}

/// <summary>
/// Gets a batch response as a requested type for the specified batch request id.
/// </summary>
/// <param name="requestId">A batch request id.</param>
/// <param name="responseHandler">ResponseHandler to use for the response</param>
/// <returns>A deserialized object of type T<see cref="HttpResponseMessage"/>.</returns>
public Task<T> GetResponseByIdAsync<T>(string requestId, IResponseHandler responseHandler = null) where T : IParsable, new()
{
return GetBatchResponseContaining(requestId)?.GetResponseByIdAsync<T>(requestId, responseHandler)
?? Task.FromResult<T>(default);
}

/// <summary>
/// Gets a batch response content as a stream
/// </summary>
/// <param name="requestId">A batch request id.</param>
/// <returns>The response stream of the batch response object</returns>
/// <remarks> Stream should be dispose once done with.</remarks>
public Task<Stream> GetResponseStreamByIdAsync(string requestId)
{
var batch = GetBatchResponseContaining(requestId);
if (batch is null)
{
return Task.FromResult<Stream>(default);
}

return batch.GetResponseStreamByIdAsync(requestId);
}

/// <summary>
/// Gets all batch responses <see cref="Dictionary{String, HttpResponseMessage}"/>.
/// All <see cref="HttpResponseMessage"/> in the dictionary MUST be disposed since they implement <see cref="IDisposable"/>.
/// </summary>
/// <returns>A Dictionary of id and <see cref="HttpResponseMessage"/> representing batch responses.</returns>
/// <remarks>Not implemented, need help</remarks>
public Task<Dictionary<string, HttpResponseMessage>> GetResponsesAsync()
{
throw new NotImplementedException("GetResponsesAsync() is not available in the BatchCollection");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace Microsoft.Graph
{
using System.Collections.Generic;

internal class KeyedBatchResponseContent
{
internal readonly HashSet<string> Keys;
internal readonly BatchResponseContent Response;

public KeyedBatchResponseContent(HashSet<string> keys, BatchResponseContent response)
{
Keys = keys;
Response = response;
}
}
}