/// <summary> /// Submit a <see cref="BlobBatch"/> of sub-operations. /// </summary> /// <param name="batch"> /// A <see cref="BlobBatch"/> of sub-operations. /// </param> /// <param name="throwOnAnyFailure"> /// A value indicating whether or not to throw exceptions for /// sub-operation failures. /// </param> /// <param name="async"> /// Whether to invoke the operation asynchronously. /// </param> /// <param name="cancellationToken"> /// Optional <see cref="CancellationToken"/> to propagate notifications /// that the operation should be cancelled. /// </param> /// <returns> /// A <see cref="Response"/> on successfully submitting. /// </returns> /// <remarks> /// A <see cref="RequestFailedException"/> will be thrown if /// a failure to submit the batch occurs. Individual sub-operation /// failures will only throw if <paramref name="throwOnAnyFailure"/> is /// true and be wrapped in an <see cref="AggregateException"/>. /// </remarks> private async Task <Response> SubmitBatchInternal( BlobBatch batch, bool throwOnAnyFailure, bool async, CancellationToken cancellationToken) { batch = batch ?? throw new ArgumentNullException(nameof(batch)); if (batch.Submitted) { throw BatchErrors.CannotResubmitBatch(nameof(batch)); } else if (!batch.IsAssociatedClient(this)) { throw BatchErrors.BatchClientDoesNotMatch(nameof(batch)); } // Get the sub-operation messages to submit IList <HttpMessage> messages = batch.GetMessagesToSubmit(); if (messages.Count == 0) { throw BatchErrors.CannotSubmitEmptyBatch(nameof(batch)); } // TODO: Consider validating the upper limit of 256 messages // Merge the sub-operations into a single multipart/mixed Stream (Stream content, string contentType) = await MergeOperationRequests( messages, async, cancellationToken) .ConfigureAwait(false); // Send the batch request Response <BlobBatchResult> batchResult = await BatchRestClient.Service.SubmitBatchAsync( ClientDiagnostics, Pipeline, Uri, body : content, contentLength : content.Length, multipartContentType : contentType, async : async, operationName : BatchConstants.BatchOperationName, cancellationToken : cancellationToken) .ConfigureAwait(false); // Split the responses apart and update the sub-operation responses Response raw = batchResult.GetRawResponse(); await UpdateOperationResponses( messages, raw, batchResult.Value.Content, batchResult.Value.ContentType, throwOnAnyFailure, async, cancellationToken) .ConfigureAwait(false); // Return the batch result return(raw); }
/// <summary> /// Submit a <see cref="BlobBatch"/> of sub-operations. /// </summary> /// <param name="batch"> /// A <see cref="BlobBatch"/> of sub-operations. /// </param> /// <param name="throwOnAnyFailure"> /// A value indicating whether or not to throw exceptions for /// sub-operation failures. /// </param> /// <param name="async"> /// Whether to invoke the operation asynchronously. /// </param> /// <param name="cancellationToken"> /// Optional <see cref="CancellationToken"/> to propagate notifications /// that the operation should be cancelled. /// </param> /// <returns> /// A <see cref="Response"/> on successfully submitting. /// </returns> /// <remarks> /// A <see cref="RequestFailedException"/> will be thrown if /// a failure to submit the batch occurs. Individual sub-operation /// failures will only throw if <paramref name="throwOnAnyFailure"/> is /// true and be wrapped in an <see cref="AggregateException"/>. /// </remarks> private async Task <Response> SubmitBatchInternal( BlobBatch batch, bool throwOnAnyFailure, bool async, CancellationToken cancellationToken) { DiagnosticScope scope = ClientDiagnostics.CreateScope($"{nameof(BlobBatchClient)}.{nameof(SubmitBatch)}"); try { scope.Start(); batch = batch ?? throw new ArgumentNullException(nameof(batch)); if (batch.Submitted) { throw BatchErrors.CannotResubmitBatch(nameof(batch)); } else if (!batch.IsAssociatedClient(this)) { throw BatchErrors.BatchClientDoesNotMatch(nameof(batch)); } // Get the sub-operation messages to submit IList <HttpMessage> messages = batch.GetMessagesToSubmit(); if (messages.Count == 0) { throw BatchErrors.CannotSubmitEmptyBatch(nameof(batch)); } // TODO: Consider validating the upper limit of 256 messages // Merge the sub-operations into a single multipart/mixed Stream (Stream content, string contentType) = await MergeOperationRequests( messages, async, cancellationToken) .ConfigureAwait(false); if (IsContainerScoped) { ResponseWithHeaders <Stream, ContainerSubmitBatchHeaders> response; if (async) { response = await _containerRestClient.SubmitBatchAsync( containerName : ContainerName, contentLength : content.Length, multipartContentType : contentType, body : content, cancellationToken : cancellationToken) .ConfigureAwait(false); } else { response = _containerRestClient.SubmitBatch( containerName: ContainerName, contentLength: content.Length, multipartContentType: contentType, body: content, cancellationToken: cancellationToken); } await UpdateOperationResponses( messages, response.GetRawResponse(), response.Value, response.Headers.ContentType, throwOnAnyFailure, async, cancellationToken) .ConfigureAwait(false); return(response.GetRawResponse()); } else { ResponseWithHeaders <Stream, ServiceSubmitBatchHeaders> response; if (async) { response = await _serviceRestClient.SubmitBatchAsync( contentLength : content.Length, multipartContentType : contentType, body : content, cancellationToken : cancellationToken) .ConfigureAwait(false); } else { response = _serviceRestClient.SubmitBatch( contentLength: content.Length, multipartContentType: contentType, body: content, cancellationToken: cancellationToken); } await UpdateOperationResponses( messages, response.GetRawResponse(), response.Value, response.Headers.ContentType, throwOnAnyFailure, async, cancellationToken) .ConfigureAwait(false); return(response.GetRawResponse()); } } catch (Exception ex) { scope.Failed(ex); throw; } finally { scope.Dispose(); } }
/// <summary> /// Submit a <see cref="BlobBatch"/> of sub-operations. /// </summary> /// <param name="batch"> /// A <see cref="BlobBatch"/> of sub-operations. /// </param> /// <param name="throwOnAnyFailure"> /// A value indicating whether or not to throw exceptions for /// sub-operation failures. /// </param> /// <param name="async"> /// Whether to invoke the operation asynchronously. /// </param> /// <param name="cancellationToken"> /// Optional <see cref="CancellationToken"/> to propagate notifications /// that the operation should be cancelled. /// </param> /// <returns> /// A <see cref="Response"/> on successfully submitting. /// </returns> /// <remarks> /// A <see cref="RequestFailedException"/> will be thrown if /// a failure to submit the batch occurs. Individual sub-operation /// failures will only throw if <paramref name="throwOnAnyFailure"/> is /// true and be wrapped in an <see cref="AggregateException"/>. /// </remarks> private async Task <Response> SubmitBatchInternal( BlobBatch batch, bool throwOnAnyFailure, bool async, CancellationToken cancellationToken) { DiagnosticScope scope = ClientDiagnostics.CreateScope($"{nameof(BlobBatchClient)}.{nameof(SubmitBatch)}"); try { scope.Start(); batch = batch ?? throw new ArgumentNullException(nameof(batch)); if (batch.Submitted) { throw BatchErrors.CannotResubmitBatch(nameof(batch)); } else if (!batch.IsAssociatedClient(this)) { throw BatchErrors.BatchClientDoesNotMatch(nameof(batch)); } // Get the sub-operation messages to submit IList <HttpMessage> messages = batch.GetMessagesToSubmit(); if (messages.Count == 0) { throw BatchErrors.CannotSubmitEmptyBatch(nameof(batch)); } // TODO: Consider validating the upper limit of 256 messages // Merge the sub-operations into a single multipart/mixed Stream (Stream content, string contentType) = await MergeOperationRequests( messages, async, cancellationToken) .ConfigureAwait(false); // Send the batch request Response <BlobBatchResult> batchResult; if (_isContainerScoped) { batchResult = await BatchRestClient.Container.SubmitBatchAsync( clientDiagnostics : ClientDiagnostics, pipeline : Pipeline, resourceUri : Uri, body : content, contentLength : content.Length, multipartContentType : contentType, version : Version.ToVersionString(), async : async, operationName : $"{nameof(BlobBatchClient)}.{nameof(SubmitBatch)}", cancellationToken : cancellationToken) .ConfigureAwait(false); } else { batchResult = await BatchRestClient.Service.SubmitBatchAsync( clientDiagnostics : ClientDiagnostics, pipeline : Pipeline, resourceUri : Uri, body : content, contentLength : content.Length, multipartContentType : contentType, version : Version.ToVersionString(), async : async, operationName : $"{nameof(BlobBatchClient)}.{nameof(SubmitBatch)}", cancellationToken : cancellationToken) .ConfigureAwait(false); } // Split the responses apart and update the sub-operation responses Response raw = batchResult.GetRawResponse(); await UpdateOperationResponses( messages, raw, batchResult.Value.Content, batchResult.Value.ContentType, throwOnAnyFailure, async, cancellationToken) .ConfigureAwait(false); // Return the batch result return(raw); } catch (Exception ex) { scope.Failed(ex); throw; } finally { scope.Dispose(); } }