diff --git a/.github/workflows/validatePullRequest.yml b/.github/workflows/validatePullRequest.yml index 04c92d6d9..c3f46c5c2 100644 --- a/.github/workflows/validatePullRequest.yml +++ b/.github/workflows/validatePullRequest.yml @@ -15,7 +15,7 @@ jobs: solutionName: Microsoft.Graph.Core.sln relativePath: ./src/Microsoft.Graph.Core steps: - - uses: actions/checkout@v3.0.2 + - uses: actions/checkout@v3.3.0 - name: Setup .NET uses: actions/setup-dotnet@v2.1.0 diff --git a/src/Microsoft.Graph.Core/Microsoft.Graph.Core.csproj b/src/Microsoft.Graph.Core/Microsoft.Graph.Core.csproj index 5660c5a3a..b5bbe5ab5 100644 --- a/src/Microsoft.Graph.Core/Microsoft.Graph.Core.csproj +++ b/src/Microsoft.Graph.Core/Microsoft.Graph.Core.csproj @@ -20,10 +20,10 @@ false 35MSSharedLib1024.snk true - 3.0.0 + 3.0.1 -- GA Release supporting Kiota +- Adds support for enhanced batch requests (https://github.com/microsoftgraph/msgraph-sdk-dotnet-core/issues/612) true true diff --git a/src/Microsoft.Graph.Core/Requests/BatchRequestBuilder.cs b/src/Microsoft.Graph.Core/Requests/BatchRequestBuilder.cs index 500dfc985..36597450f 100644 --- a/src/Microsoft.Graph.Core/Requests/BatchRequestBuilder.cs +++ b/src/Microsoft.Graph.Core/Requests/BatchRequestBuilder.cs @@ -52,6 +52,26 @@ public async Task PostAsync(BatchRequestContent batchReque return new BatchResponseContent(nativeResponseHandler.Value as HttpResponseMessage); } + /// + /// Sends out the using the POST method + /// + /// The for the request + /// to use for cancelling requests + /// + public async Task 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; + } + /// /// Create instance to post to batch endpoint /// The for the request diff --git a/src/Microsoft.Graph.Core/Requests/Content/BatchRequestContentCollection.cs b/src/Microsoft.Graph.Core/Requests/Content/BatchRequestContentCollection.cs new file mode 100644 index 000000000..52a4bbcae --- /dev/null +++ b/src/Microsoft.Graph.Core/Requests/Content/BatchRequestContentCollection.cs @@ -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; + + /// + /// A collection of batch requests that are automatically managed. + /// + public class BatchRequestContentCollection + { + private readonly IBaseClient baseClient; + private readonly List batchRequests; + private BatchRequestContent currentRequest; + private bool readOnly = false; + + /// + /// Constructs a new . + /// + /// The for making requests + public BatchRequestContentCollection(IBaseClient baseClient) + { + this.baseClient = baseClient; + batchRequests = new List(); + 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); + } + } + + /// + /// Adds a to batch request content. + /// + /// A to use to build a to add. + /// The requestId of the newly created + public string AddBatchRequestStep(HttpRequestMessage httpRequestMessage) + { + SetupCurrentRequest(); + return currentRequest.AddBatchRequestStep(httpRequestMessage); + } + + /// + /// Adds a to batch request content + /// + /// A to use to build a to add. + /// The requestId of the newly created + public Task AddBatchRequestStepAsync(RequestInformation requestInformation) + { + SetupCurrentRequest(); + return currentRequest.AddBatchRequestStepAsync(requestInformation); + } + + /// + /// Removes a from batch request content for the specified id. + /// + /// A unique batch request id to remove. + /// True or false based on removal or not removal of a . + 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 GetBatchRequestsForExecution() + { + readOnly = true; + if (currentRequest.BatchRequestSteps.Count > 0) + { + batchRequests.Add(currentRequest); + } + + return batchRequests; + } + } +} \ No newline at end of file diff --git a/src/Microsoft.Graph.Core/Requests/Content/BatchResponseContentCollection.cs b/src/Microsoft.Graph.Core/Requests/Content/BatchResponseContentCollection.cs new file mode 100644 index 000000000..94db00c01 --- /dev/null +++ b/src/Microsoft.Graph.Core/Requests/Content/BatchResponseContentCollection.cs @@ -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; + + /// + /// Handles batch request responses. + /// + public class BatchResponseContentCollection + { + private readonly List batchResponses; + + internal BatchResponseContentCollection() + { + batchResponses = new List(); + } + + internal void AddResponse(IEnumerable keys, BatchResponseContent content) + { + batchResponses.Add(new KeyedBatchResponseContent(new HashSet(keys), content)); + } + + private BatchResponseContent GetBatchResponseContaining(string requestId) + { + return batchResponses.FirstOrDefault(b => b.Keys.Contains(requestId))?.Response; + } + + /// + /// Gets a batch response as for the specified batch request id. + /// The returned MUST be disposed since it implements an . + /// + /// A batch request id. + /// A response object for a batch request. + public Task GetResponseByIdAsync(string requestId) + { + return GetBatchResponseContaining(requestId)?.GetResponseByIdAsync(requestId) + ?? Task.FromResult(null); + } + + /// + /// Gets a batch response as a requested type for the specified batch request id. + /// + /// A batch request id. + /// ResponseHandler to use for the response + /// A deserialized object of type T. + public Task GetResponseByIdAsync(string requestId, IResponseHandler responseHandler = null) where T : IParsable, new() + { + return GetBatchResponseContaining(requestId)?.GetResponseByIdAsync(requestId, responseHandler) + ?? Task.FromResult(default); + } + + /// + /// Gets a batch response content as a stream + /// + /// A batch request id. + /// The response stream of the batch response object + /// Stream should be dispose once done with. + public Task GetResponseStreamByIdAsync(string requestId) + { + var batch = GetBatchResponseContaining(requestId); + if (batch is null) + { + return Task.FromResult(default); + } + + return batch.GetResponseStreamByIdAsync(requestId); + } + + /// + /// Gets all batch responses . + /// All in the dictionary MUST be disposed since they implement . + /// + /// A Dictionary of id and representing batch responses. + /// Not implemented, need help + public Task> GetResponsesAsync() + { + throw new NotImplementedException("GetResponsesAsync() is not available in the BatchCollection"); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.Graph.Core/Requests/Content/KeyedBatchResponseContent.cs b/src/Microsoft.Graph.Core/Requests/Content/KeyedBatchResponseContent.cs new file mode 100644 index 000000000..0f7daaf01 --- /dev/null +++ b/src/Microsoft.Graph.Core/Requests/Content/KeyedBatchResponseContent.cs @@ -0,0 +1,16 @@ +namespace Microsoft.Graph +{ + using System.Collections.Generic; + + internal class KeyedBatchResponseContent + { + internal readonly HashSet Keys; + internal readonly BatchResponseContent Response; + + public KeyedBatchResponseContent(HashSet keys, BatchResponseContent response) + { + Keys = keys; + Response = response; + } + } +} \ No newline at end of file