/// <summary> /// The <see cref="StageBlockAsync"/> operation creates a new block as /// part of a block blob's "staging area" to be eventually committed /// via the <see cref="CommitBlockListAsync"/> operation. /// /// For more information, see <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/put-block" />. /// </summary> /// <param name="base64BlockID"> /// A valid Base64 string value that identifies the block. Prior to /// encoding, the string must be less than or equal to 64 bytes in /// size. /// /// For a given blob, the length of the value specified for the /// blockid parameter must be the same size for each block. Note that /// the Base64 string must be URL-encoded. /// </param> /// <param name="content"> /// A <see cref="Stream"/> containing the content to upload. /// </param> /// <param name="transactionalContentHash"> /// An optional MD5 hash of the block <paramref name="content"/>. /// This hash is used to verify the integrity of the block during /// transport. When this value is specified, the storage service /// compares the hash of the content that has arrived with this value. /// Note that this MD5 hash is not stored with the blob. If the two /// hashes do not match, the operation will throw a /// <see cref="StorageRequestFailedException"/>. /// </param> /// <param name="leaseAccessConditions"> /// Optional <see cref="LeaseAccessConditions"/> to add /// conditions on the upload of this block. /// </param> /// <param name="progressHandler"> /// Optional <see cref="IProgress{StorageProgress}"/> to provide /// progress updates about data transfers. /// </param> /// <returns> /// A <see cref="Task{Response{BlobContentInfo}}"/> describing the /// state of the updated block blob. /// </returns> /// <remarks> /// A <see cref="StorageRequestFailedException"/> will be thrown if /// a failure occurs. /// </remarks> public async Task <Response <BlobContentInfo> > StageBlockAsync( string base64BlockID, Stream content, byte[] transactionalContentHash = default, LeaseAccessConditions?leaseAccessConditions = default, IProgress <StorageProgress> progressHandler = default, CancellationToken cancellation = default) { using (this.Pipeline.BeginLoggingScope(nameof(BlockBlobClient))) { this.Pipeline.LogMethodEnter( nameof(BlockBlobClient), message: $"{nameof(this.Uri)}: {this.Uri}\n" + $"{nameof(base64BlockID)}: {base64BlockID}\n" + $"{nameof(leaseAccessConditions)}: {leaseAccessConditions}"); try { content = content.WithNoDispose().WithProgress(progressHandler); var uploadAttempt = 0; return(await ReliableOperation.DoAsync( reset : () => content.Seek(0, SeekOrigin.Begin), predicate : e => true, maximumRetries : Constants.MaxReliabilityRetries, operation : async() => { this.Pipeline.LogTrace($"Upload attempt {++uploadAttempt}"); return await BlobRestClient.BlockBlob.StageBlockAsync( this.Pipeline, this.Uri, blockId: base64BlockID, body: content, contentLength: content.Length, transactionalContentHash: transactionalContentHash, leaseId: leaseAccessConditions?.LeaseId, cancellation: cancellation) .ConfigureAwait(false); }, cleanup : () => { }) .ConfigureAwait(false)); } catch (Exception ex) { this.Pipeline.LogException(ex); throw; } finally { this.Pipeline.LogMethodExit(nameof(BlockBlobClient)); } } }
public static Task <TResult> WithRetry <TResult>(this StorageTask <TResult> task, int maximumRetries = Constants.MaxReliabilityRetries) => ReliableOperation.DoAsync( operation: () => task.StorageTaskState.InvokeAsync(), reliabilityConfiguration: task.StorageTaskState.ReliabilityConfiguration, maximumRetries: maximumRetries );