/// <summary> /// The SetBlobsAccessTierAsync operation sets the tier on blobs. The /// operation is allowed on block blobs in a blob storage or general /// purpose v2 account. /// </summary> /// <param name="blobUris"> /// URIs of the blobs to set the tiers of. /// </param> /// <param name="accessTier"> /// Indicates the tier to be set on the blobs. /// </param> /// <param name="rehydratePriority"> /// Optional <see cref="RehydratePriority"/> /// Indicates the priority with which to rehydrate an archived blob. /// </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> /// The <see cref="Response"/>s for the individual Set Tier operations. /// </returns> /// <remarks> /// A <see cref="RequestFailedException"/> will be thrown if /// a failure to submit the batch occurs. Individual sub-operation /// failures will be wrapped in an <see cref="AggregateException"/>. /// </remarks> internal async Task <Response[]> SetBlobsAccessTierInteral( IEnumerable <Uri> blobUris, AccessTier accessTier, RehydratePriority?rehydratePriority, bool async, CancellationToken cancellationToken) { DiagnosticScope scope = ClientDiagnostics.CreateScope($"{nameof(BlobBatchClient)}.{nameof(SetBlobsAccessTier)}"); try { scope.Start(); blobUris = blobUris ?? throw new ArgumentNullException(nameof(blobUris)); var responses = new List <Response>(); // Create the batch BlobBatch batch = CreateBatch(); foreach (Uri uri in blobUris) { responses.Add(batch.SetBlobAccessTier(uri, accessTier, rehydratePriority)); } // Submit the batch await SubmitBatchInternal( batch, true, async, cancellationToken) .ConfigureAwait(false); return(responses.ToArray()); } catch (Exception ex) { scope.Failed(ex); throw; } finally { scope.Dispose(); } }
/// <summary> /// The DeleteBlobsAsync operation marks the specified blobs for /// deletion. The blobs are later deleted during garbage collection /// which could take several minutes. /// All of the deletions are sent as a single batched request. /// </summary> /// <param name="blobUris">URIs of the blobs to delete.</param> /// <param name="snapshotsOption"> /// Specifies options for deleting blob snapshots. /// </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> /// The <see cref="Response"/>s for the individual Delete operations. /// </returns> /// <remarks> /// A <see cref="RequestFailedException"/> will be thrown if /// a failure to submit the batch occurs. Individual sub-operation /// failures will be wrapped in an <see cref="AggregateException"/>. /// </remarks> internal async Task <Response[]> DeleteBlobsInteral( IEnumerable <Uri> blobUris, DeleteSnapshotsOption snapshotsOption, bool async, CancellationToken cancellationToken) { DiagnosticScope scope = ClientDiagnostics.CreateScope($"{nameof(BlobBatchClient)}.{nameof(DeleteBlobs)}"); try { scope.Start(); blobUris = blobUris ?? throw new ArgumentNullException(nameof(blobUris)); var responses = new List <Response>(); // Create the batch BlobBatch batch = CreateBatch(); foreach (Uri uri in blobUris) { responses.Add(batch.DeleteBlob(uri, snapshotsOption)); } // Submit the batch await SubmitBatchInternal( batch, true, async, cancellationToken) .ConfigureAwait(false); return(responses.ToArray()); } 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) { 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(); } }