< Summary

Class:Azure.Storage.Blobs.Specialized.BlockBlobClient
Assembly:Azure.Storage.Blobs
File(s):C:\Git\azure-sdk-for-net\sdk\storage\Azure.Storage.Blobs\src\BlockBlobClient.cs
Covered lines:386
Uncovered lines:21
Coverable lines:407
Total lines:2111
Line coverage:94.8% (386 of 407)
Covered branches:147
Total branches:174
Branch coverage:84.4% (147 of 174)

Metrics

MethodCyclomatic complexity Line coverage Branch coverage
get_BlockBlobMaxUploadBlobBytes()-0%0%
get_BlockBlobMaxUploadBlobLongBytes()-0%0%
get_BlockBlobMaxStageBlockBytes()-0%0%
get_BlockBlobMaxStageBlockLongBytes()-0%0%
get_BlockBlobMaxBlocks()-0%100%
.ctor()-100%100%
.ctor(...)-0%100%
.ctor(...)-100%100%
.ctor(...)-100%100%
.ctor(...)-0%100%
.ctor(...)-33.33%100%
.ctor(...)-100%100%
CreateClient(...)-100%100%
AssertNoClientSideEncryption(...)-66.67%75%
WithSnapshot(...)-100%100%
WithVersion(...)-100%100%
WithSnapshotCore(...)-100%100%
Upload(...)-100%50%
UploadAsync()-100%50%
Upload(...)-100%100%
UploadAsync()-100%100%
UploadInternal()-100%92.11%
StageBlock(...)-100%100%
StageBlockAsync()-100%100%
StageBlockInternal()-100%100%
StageBlockFromUri(...)-100%100%
StageBlockFromUriAsync()-100%100%
StageBlockFromUriInternal()-100%100%
CommitBlockList(...)-100%50%
CommitBlockList(...)-100%100%
CommitBlockListAsync()-100%50%
CommitBlockListAsync()-100%100%
CommitBlockListInternal()-100%100%
GetBlockList(...)-100%100%
GetBlockListAsync()-100%100%
GetBlockListInternal()-100%100%
Query(...)-100%100%
QueryAsync()-100%100%
QueryInternal()-100%92.11%
GetPartitionedUploader(...)-100%100%
GetPartitionedUploaderBehaviors(...)-100%100%

File(s)

C:\Git\azure-sdk-for-net\sdk\storage\Azure.Storage.Blobs\src\BlockBlobClient.cs

#LineLine coverage
 1// Copyright (c) Microsoft Corporation. All rights reserved.
 2// Licensed under the MIT License.
 3
 4using System;
 5using System.Buffers;
 6using System.Collections.Generic;
 7using System.ComponentModel;
 8using System.Diagnostics;
 9using System.Globalization;
 10using System.IO;
 11using System.Linq;
 12using System.Threading;
 13using System.Threading.Tasks;
 14using Azure.Core;
 15using Azure.Core.Pipeline;
 16using Azure.Storage.Blobs.Models;
 17using Metadata = System.Collections.Generic.IDictionary<string, string>;
 18using Tags = System.Collections.Generic.IDictionary<string, string>;
 19
 20#pragma warning disable SA1402  // File may only contain a single type
 21
 22namespace Azure.Storage.Blobs.Specialized
 23{
 24    /// <summary>
 25    /// The <see cref="BlockBlobClient"/> allows you to manipulate Azure
 26    /// Storage block blobs.
 27    ///
 28    /// Block blobs let you upload large blobs efficiently.  Block blobs are
 29    /// comprised of blocks, each of which is identified by a block ID. You
 30    /// create or modify a block blob by writing a set of blocks and
 31    /// committing them by their block IDs. Each block can be a different
 32    /// size, up to a maximum of 4,000 MB (100 MB for requests using REST
 33    /// versions before 2019-12-12 and 4 MB for requests using REST versions
 34    /// before 2016-05-31), and a block blob can include up to 50,000 blocks.
 35    /// The maximum size of a block blob is therefore approximately 190.73 TiB
 36    /// (4,000 MB X 50,000 blocks).  If you are writing a block blob that is
 37    /// no more than 5,000 MB in size, you can upload it in its entirety with a
 38    /// single write operation; see <see cref="BlockBlobClient.UploadAsync(Stream, BlobHttpHeaders, Metadata, BlobReques
 39    ///
 40    /// When you upload a block to a blob in your storage account, it is
 41    /// associated with the specified block blob, but it does not become part
 42    /// of the blob until you commit a list of blocks that includes the new
 43    /// block's ID. New blocks remain in an uncommitted state until they are
 44    /// specifically committed or discarded. Writing a block does not update
 45    /// the last modified time of an existing blob.
 46    ///
 47    /// Block blobs include features that help you manage large files over
 48    /// networks.  With a block blob, you can upload multiple blocks in
 49    /// parallel to decrease upload time.  Each block can include an MD5 hash
 50    /// to verify the transfer, so you can track upload progress and re-send
 51    /// blocks as needed.You can upload blocks in any order, and determine
 52    /// their sequence in the final block list commitment step. You can also
 53    /// upload a new block to replace an existing uncommitted block of the
 54    /// same block ID.  You have one week to commit blocks to a blob before
 55    /// they are discarded.  All uncommitted blocks are also discarded when a
 56    /// block list commitment operation occurs but does not include them.
 57    ///
 58    /// You can modify an existing block blob by inserting, replacing, or
 59    /// deleting existing blocks. After uploading the block or blocks that
 60    /// have changed, you can commit a new version of the blob by committing
 61    /// the new blocks with the existing blocks you want to keep using a
 62    /// single commit operation. To insert the same range of bytes in two
 63    /// different locations of the committed blob, you can commit the same
 64    /// block in two places within the same commit operation.For any commit
 65    /// operation, if any block is not found, the entire commitment operation
 66    /// fails with an error, and the blob is not modified. Any block commitment
 67    /// overwrites the blob’s existing properties and metadata, and discards
 68    /// all uncommitted blocks.
 69    ///
 70    /// Block IDs are strings of equal length within a blob. Block client code
 71    /// usually uses base-64 encoding to normalize strings into equal lengths.
 72    /// When using base-64 encoding, the pre-encoded string must be 64 bytes
 73    /// or less.  Block ID values can be duplicated in different blobs.  A
 74    /// blob can have up to 100,000 uncommitted blocks, with a max total size
 75    /// of appoximately 381.46 TiB (4,000 MB x 100,000 blocks)
 76    ///
 77    /// If you write a block for a blob that does not exist, a new block blob
 78    /// is created, with a length of zero bytes.  This blob will appear in
 79    /// blob lists that include uncommitted blobs.  If you don’t commit any
 80    /// block to this blob, it and its uncommitted blocks will be discarded
 81    /// one week after the last successful block upload. All uncommitted
 82    /// blocks are also discarded when a new blob of the same name is created
 83    /// using a single step(rather than the two-step block upload-then-commit
 84    /// process).
 85    /// </summary>
 86    public class BlockBlobClient : BlobBaseClient
 87    {
 88        /// <summary>
 89        /// Gets the maximum number of bytes that can be sent in a call
 90        /// to <see cref="UploadAsync(Stream, BlobUploadOptions, CancellationToken)"/>. Supported value is now larger
 91        /// than <see cref="int.MaxValue"/>; please use
 92        /// <see cref="BlockBlobMaxUploadBlobLongBytes"/>.
 93        /// </summary>
 94        [EditorBrowsable(EditorBrowsableState.Never)]
 095        public virtual int BlockBlobMaxUploadBlobBytes => Version < BlobClientOptions.ServiceVersion.V2019_12_12
 096            ? Constants.Blob.Block.Pre_2019_12_12_MaxUploadBytes
 097            : int.MaxValue; // value is larger than can be represented by an int
 98
 99        /// <summary>
 100        /// Gets the maximum number of bytes that can be sent in a call
 101        /// to <see cref="UploadAsync(Stream, BlobUploadOptions, CancellationToken)"/>.
 102        /// </summary>
 0103        public virtual long BlockBlobMaxUploadBlobLongBytes => Version < BlobClientOptions.ServiceVersion.V2019_12_12
 0104            ? Constants.Blob.Block.Pre_2019_12_12_MaxUploadBytes
 0105            : Constants.Blob.Block.MaxUploadBytes;
 106
 107        /// <summary>
 108        /// Gets the maximum number of bytes that can be sent in a call
 109        /// to <see cref="StageBlockAsync"/>. Supported value is now larger
 110        /// than <see cref="int.MaxValue"/>; please use
 111        /// <see cref="BlockBlobMaxStageBlockLongBytes"/>.
 112        /// </summary>
 113        [EditorBrowsable(EditorBrowsableState.Never)]
 0114        public virtual int BlockBlobMaxStageBlockBytes => Version < BlobClientOptions.ServiceVersion.V2019_12_12
 0115            ? Constants.Blob.Block.Pre_2019_12_12_MaxStageBytes
 0116            : int.MaxValue; // value is larger than can be represented by an int
 117
 118        /// <summary>
 119        /// Gets the maximum number of bytes that can be sent in a call
 120        /// to <see cref="StageBlockAsync"/>.
 121        /// </summary>
 0122        public virtual long BlockBlobMaxStageBlockLongBytes => Version < BlobClientOptions.ServiceVersion.V2019_12_12
 0123            ? Constants.Blob.Block.Pre_2019_12_12_MaxStageBytes
 0124            : Constants.Blob.Block.MaxStageBytes;
 125
 126        /// <summary>
 127        /// Gets the maximum number of blocks allowed in a block blob.
 128        /// </summary>
 0129        public virtual int BlockBlobMaxBlocks => Constants.Blob.Block.MaxBlocks;
 130
 131        #region ctors
 132        /// <summary>
 133        /// Initializes a new instance of the <see cref="BlockBlobClient"/>
 134        /// class for mocking.
 135        /// </summary>
 2320136        protected BlockBlobClient()
 137        {
 2320138        }
 139
 140        /// <summary>
 141        /// Initializes a new instance of the <see cref="BlockBlobClient"/>
 142        /// class.
 143        /// </summary>
 144        /// <param name="connectionString">
 145        /// A connection string includes the authentication information
 146        /// required for your application to access data in an Azure Storage
 147        /// account at runtime.
 148        ///
 149        /// For more information,
 150        /// <see href="https://docs.microsoft.com/azure/storage/common/storage-configure-connection-string">
 151        /// Configure Azure Storage connection strings</see>
 152        /// </param>
 153        /// <param name="containerName">
 154        /// The name of the container containing this block blob.
 155        /// </param>
 156        /// <param name="blobName">
 157        /// The name of this block blob.
 158        /// </param>
 159        public BlockBlobClient(string connectionString, string containerName, string blobName)
 0160            : base(connectionString, containerName, blobName)
 161        {
 0162        }
 163
 164        /// <summary>
 165        /// Initializes a new instance of the <see cref="BlockBlobClient"/>
 166        /// class.
 167        /// </summary>
 168        /// <param name="connectionString">
 169        /// A connection string includes the authentication information
 170        /// required for your application to access data in an Azure Storage
 171        /// account at runtime.
 172        ///
 173        /// For more information,
 174        /// <see href="https://docs.microsoft.com/azure/storage/common/storage-configure-connection-string">
 175        /// Configure Azure Storage connection strings</see>
 176        /// </param>
 177        /// <param name="blobContainerName">
 178        /// The name of the container containing this block blob.
 179        /// </param>
 180        /// <param name="blobName">
 181        /// The name of this block blob.
 182        /// </param>
 183        /// <param name="options">
 184        /// Optional client options that define the transport pipeline
 185        /// policies for authentication, retries, etc., that are applied to
 186        /// every request.
 187        /// </param>
 188        public BlockBlobClient(string connectionString, string blobContainerName, string blobName, BlobClientOptions opt
 20189            : base(connectionString, blobContainerName, blobName, options)
 190        {
 20191            AssertNoClientSideEncryption(options);
 20192        }
 193
 194        /// <summary>
 195        /// Initializes a new instance of the <see cref="BlockBlobClient"/>
 196        /// class.
 197        /// </summary>
 198        /// <param name="blobUri">
 199        /// A <see cref="Uri"/> referencing the block blob that includes the
 200        /// name of the account, the name of the container, and the name of
 201        /// the blob.
 202        /// </param>
 203        /// <param name="options">
 204        /// Optional client options that define the transport pipeline
 205        /// policies for authentication, retries, etc., that are applied to
 206        /// every request.
 207        /// </param>
 208        public BlockBlobClient(Uri blobUri, BlobClientOptions options = default)
 68209            : base(blobUri, options)
 210        {
 64211            AssertNoClientSideEncryption(options);
 64212        }
 213
 214        /// <summary>
 215        /// Initializes a new instance of the <see cref="BlockBlobClient"/>
 216        /// class.
 217        /// </summary>
 218        /// <param name="blobUri">
 219        /// A <see cref="Uri"/> referencing the blob that includes the
 220        /// name of the account, the name of the container, and the name of
 221        /// the blob.
 222        /// </param>
 223        /// <param name="credential">
 224        /// The shared key credential used to sign requests.
 225        /// </param>
 226        /// <param name="options">
 227        /// Optional client options that define the transport pipeline
 228        /// policies for authentication, retries, etc., that are applied to
 229        /// every request.
 230        /// </param>
 231        public BlockBlobClient(Uri blobUri, StorageSharedKeyCredential credential, BlobClientOptions options = default)
 0232            : base(blobUri, credential, options)
 233        {
 0234            AssertNoClientSideEncryption(options);
 0235        }
 236
 237        /// <summary>
 238        /// Initializes a new instance of the <see cref="BlockBlobClient"/>
 239        /// class.
 240        /// </summary>
 241        /// <param name="blobUri">
 242        /// A <see cref="Uri"/> referencing the blob that includes the
 243        /// name of the account, the name of the container, and the name of
 244        /// the blob.
 245        /// </param>
 246        /// <param name="credential">
 247        /// The token credential used to sign requests.
 248        /// </param>
 249        /// <param name="options">
 250        /// Optional client options that define the transport pipeline
 251        /// policies for authentication, retries, etc., that are applied to
 252        /// every request.
 253        /// </param>
 254        public BlockBlobClient(Uri blobUri, TokenCredential credential, BlobClientOptions options = default)
 4255            : base(blobUri, credential, options)
 256        {
 0257            AssertNoClientSideEncryption(options);
 0258        }
 259
 260        /// <summary>
 261        /// Initializes a new instance of the <see cref="BlockBlobClient"/>
 262        /// class.
 263        /// </summary>
 264        /// <param name="blobUri">
 265        /// A <see cref="Uri"/> referencing the block blob that includes the
 266        /// name of the account, the name of the container, and the name of
 267        /// the blob.
 268        /// </param>
 269        /// <param name="pipeline">
 270        /// The transport pipeline used to send every request.
 271        /// </param>
 272        /// <param name="version">
 273        /// The version of the service to use when sending requests.
 274        /// </param>
 275        /// <param name="clientDiagnostics">Client diagnostics.</param>
 276        /// <param name="customerProvidedKey">Customer provided key.</param>
 277        /// <param name="encryptionScope">Encryption scope.</param>
 278        internal BlockBlobClient(
 279            Uri blobUri,
 280            HttpPipeline pipeline,
 281            BlobClientOptions.ServiceVersion version,
 282            ClientDiagnostics clientDiagnostics,
 283            CustomerProvidedKey? customerProvidedKey,
 284            string encryptionScope)
 9762285            : base(
 9762286                  blobUri,
 9762287                  pipeline,
 9762288                  version,
 9762289                  clientDiagnostics,
 9762290                  customerProvidedKey,
 9762291                  clientSideEncryption: default,
 9762292                  encryptionScope)
 293        {
 9762294        }
 295
 296        /// <summary>
 297        /// Initializes a new instance of the <see cref="BlockBlobClient"/>
 298        /// class.
 299        /// </summary>
 300        /// <param name="blobUri">
 301        /// A <see cref="Uri"/> referencing the block blob that includes the
 302        /// name of the account, the name of the container, and the name of
 303        /// the blob.
 304        /// </param>
 305        /// <param name="options">
 306        /// Optional client options that define the transport pipeline
 307        /// policies for authentication, retries, etc., that are applied to
 308        /// every request.
 309        /// </param>
 310        /// <param name="pipeline">
 311        /// The transport pipeline used to send every request.
 312        /// </param>
 313        /// <returns>
 314        /// New instanc of the <see cref="BlockBlobClient"/> class.
 315        /// </returns>
 316        protected static BlockBlobClient CreateClient(Uri blobUri, BlobClientOptions options, HttpPipeline pipeline)
 317        {
 4462318            return new BlockBlobClient(blobUri, pipeline, options.Version, new ClientDiagnostics(options), null, null);
 319        }
 320
 321        private static void AssertNoClientSideEncryption(BlobClientOptions options)
 322        {
 84323            if (options?._clientSideEncryptionOptions != default)
 324            {
 0325                throw Errors.ClientSideEncryption.TypeNotSupported(typeof(BlockBlobClient));
 326            }
 84327        }
 328        #endregion ctors
 329
 330        /// <summary>
 331        /// Initializes a new instance of the <see cref="BlockBlobClient"/>
 332        /// class with an identical <see cref="Uri"/> source but the specified
 333        /// <paramref name="snapshot"/> timestamp.
 334        ///
 335        /// For more information, see
 336        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/creating-a-snapshot-of-a-blob">
 337        /// Create a snapshot of a blob</see>.
 338        /// </summary>
 339        /// <param name="snapshot">The snapshot identifier.</param>
 340        /// <returns>A new <see cref="BlockBlobClient"/> instance.</returns>
 341        /// <remarks>
 342        /// Pass null or empty string to remove the snapshot returning a URL
 343        /// to the base blob.
 344        /// </remarks>
 16345        public new BlockBlobClient WithSnapshot(string snapshot) => (BlockBlobClient)WithSnapshotCore(snapshot);
 346
 347        /// <summary>
 348        /// Initializes a new instance of the <see cref="BlockBlobClient"/>
 349        /// class with an identical <see cref="Uri"/> source but the specified
 350        /// <paramref name="versionId"/> timestamp.
 351        ///
 352        /// </summary>
 353        /// <param name="versionId">The version identifier.</param>
 354        /// <returns>A new <see cref="BlockBlobClient"/> instance.</returns>
 355        /// <remarks>
 356        /// Pass null or empty string to remove the snapshot returning a URL
 357        /// to the base blob.
 358        /// </remarks>
 359        public new BlockBlobClient WithVersion(string versionId)
 360        {
 12361            var builder = new BlobUriBuilder(Uri) { VersionId = versionId };
 12362            return new BlockBlobClient(builder.ToUri(), Pipeline, Version, ClientDiagnostics, CustomerProvidedKey, Encry
 363        }
 364
 365        /// <summary>
 366        /// Creates a new instance of the <see cref="BlockBlobClient"/> class
 367        /// with an identical <see cref="Uri"/> source but the specified
 368        /// <paramref name="snapshot"/> timestamp.
 369        /// </summary>
 370        /// <param name="snapshot">The snapshot identifier.</param>
 371        /// <returns>A new <see cref="BlockBlobClient"/> instance.</returns>
 372        protected sealed override BlobBaseClient WithSnapshotCore(string snapshot)
 373        {
 28374            var builder = new BlobUriBuilder(Uri) { Snapshot = snapshot };
 375
 28376            return new BlockBlobClient(builder.ToUri(), Pipeline, Version, ClientDiagnostics, CustomerProvidedKey, Encry
 377        }
 378
 379        ///// <summary>
 380        ///// Creates a new BlockBlobURL object identical to the source but with the specified version ID.
 381        ///// </summary>
 382        ///// <remarks>
 383        ///// Pass null or empty string to remove the snapshot returning a URL to the base blob.
 384        ///// </remarks>
 385        ///// <param name="versionId">A string of the version identifier.</param>
 386        ///// <returns></returns>
 387        //public new BlockBlobClient WithVersionId(string versionId) => (BlockBlobUri)this.WithVersionIdImpl(versionId);
 388
 389        //protected sealed override Blobclient WithVersionIdImpl(string versionId)
 390        //{
 391        //    var builder = new BlobUriBuilder(this.Uri) { VersionId = versionId };
 392        //    return new BlockBlobClient(builder.ToUri(), this.Pipeline);
 393        //}
 394
 395        #region Upload
 396        /// <summary>
 397        /// The <see cref="Upload(Stream, BlobUploadOptions, CancellationToken)"/>
 398        /// operation creates a new block  blob,  or updates the content of an existing block blob.
 399        /// Updating an existing block blob overwrites any existing metadata on the blob.
 400        ///
 401        /// Partial updates are not supported with <see cref="Upload(Stream, BlobUploadOptions, CancellationToken)"/>;
 402        /// the content of the existing blob is overwritten with the content
 403        /// of the new blob.  To perform a partial update of the content of a
 404        /// block blob, use the <see cref="StageBlock"/> and
 405        /// <see cref="CommitBlockList(IEnumerable{string}, CommitBlockListOptions, CancellationToken)" /> operations.
 406        ///
 407        /// For more information, see
 408        /// <see href="https://docs.microsoft.com/rest/api/storageservices/put-blob">
 409        /// Put Blob</see>.
 410        /// </summary>
 411        /// <param name="content">
 412        /// A <see cref="Stream"/> containing the content to upload.
 413        /// </param>
 414        /// <param name="options">
 415        /// Optional parameters.
 416        /// </param>
 417        /// <param name="cancellationToken">
 418        /// Optional <see cref="CancellationToken"/> to propagate
 419        /// notifications that the operation should be cancelled.
 420        /// </param>
 421        /// <returns>
 422        /// A <see cref="Response{BlobContentInfo}"/> describing the
 423        /// state of the updated block blob.
 424        /// </returns>
 425        /// <remarks>
 426        /// A <see cref="RequestFailedException"/> will be thrown if
 427        /// a failure occurs.
 428        /// </remarks>
 429        public virtual Response<BlobContentInfo> Upload(
 430            Stream content,
 431            BlobUploadOptions options,
 432            CancellationToken cancellationToken = default)
 433        {
 904434            var uploader = GetPartitionedUploader(
 904435                transferOptions: options?.TransferOptions ?? default,
 904436                operationName: $"{nameof(BlockBlobClient)}.{nameof(Upload)}");
 437
 904438            return uploader.UploadInternal(
 904439                content,
 904440                options,
 904441                options.ProgressHandler,
 904442                async: false,
 904443                cancellationToken).EnsureCompleted();
 444        }
 445
 446        /// <summary>
 447        /// The <see cref="UploadAsync(Stream, BlobUploadOptions, CancellationToken)"/>
 448        /// operation creates a new block  blob,  or updates the content of an existing block blob.
 449        /// Updating an existing block blob overwrites any existing metadata on the blob.
 450        ///
 451        /// Partial updates are not supported with <see cref="UploadAsync(Stream, BlobUploadOptions, CancellationToken)"
 452        /// the content of the existing blob is overwritten with the content
 453        /// of the new blob.  To perform a partial update of the content of a
 454        /// block blob, use the <see cref="StageBlock"/> and
 455        /// <see cref="CommitBlockListAsync(IEnumerable{string}, CommitBlockListOptions, CancellationToken)" /> operatio
 456        ///
 457        /// For more information, see
 458        /// <see href="https://docs.microsoft.com/rest/api/storageservices/put-blob">
 459        /// Put Blob</see>.
 460        /// </summary>
 461        /// <param name="content">
 462        /// A <see cref="Stream"/> containing the content to upload.
 463        /// </param>
 464        /// <param name="options">
 465        /// Optional parameters.
 466        /// </param>
 467        /// <param name="cancellationToken">
 468        /// Optional <see cref="CancellationToken"/> to propagate
 469        /// notifications that the operation should be cancelled.
 470        /// </param>
 471        /// <returns>
 472        /// A <see cref="Response{BlobContentInfo}"/> describing the
 473        /// state of the updated block blob.
 474        /// </returns>
 475        /// <remarks>
 476        /// A <see cref="RequestFailedException"/> will be thrown if
 477        /// a failure occurs.
 478        /// </remarks>
 479        public virtual async Task<Response<BlobContentInfo>> UploadAsync(
 480            Stream content,
 481            BlobUploadOptions options,
 482            CancellationToken cancellationToken = default)
 483        {
 944484            var uploader = GetPartitionedUploader(
 944485                transferOptions: options?.TransferOptions ?? default,
 944486                operationName: $"{nameof(BlockBlobClient)}.{nameof(Upload)}");
 487
 944488            return await uploader.UploadInternal(
 944489                content,
 944490                options,
 944491                options.ProgressHandler,
 944492                async: true,
 944493                cancellationToken)
 944494                .ConfigureAwait(false);
 930495        }
 496
 497        /// <summary>
 498        /// The <see cref="Upload(Stream, BlobHttpHeaders, Metadata, BlobRequestConditions, AccessTier?, IProgress{long}
 499        /// operation creates a new block  blob, or updates the content of an existing block blob.  Updating an
 500        /// existing block blob overwrites any existing metadata on the blob.
 501        ///
 502        /// Partial updates are not supported with <see cref="Upload(Stream, BlobHttpHeaders, Metadata, BlobRequestCondi
 503        /// the content of the existing blob is overwritten with the content
 504        /// of the new blob.  To perform a partial update of the content of a
 505        /// block blob, use the <see cref="StageBlock"/> and
 506        /// <see cref="CommitBlockList(IEnumerable{string}, BlobHttpHeaders, Metadata, BlobRequestConditions, AccessTier
 507        ///
 508        /// For more information, see
 509        /// <see href="https://docs.microsoft.com/rest/api/storageservices/put-blob">
 510        /// Put Blob</see>.
 511        /// </summary>
 512        /// <param name="content">
 513        /// A <see cref="Stream"/> containing the content to upload.
 514        /// </param>
 515        /// <param name="httpHeaders">
 516        /// Optional standard HTTP header properties that can be set for the
 517        /// block blob.
 518        /// </param>
 519        /// <param name="metadata">
 520        /// Optional custom metadata to set for this block blob.
 521        /// </param>
 522        /// <param name="conditions">
 523        /// Optional <see cref="BlockBlobClient"/> to add
 524        /// conditions on the creation of this new block blob.
 525        /// </param>
 526        /// <param name="accessTier">
 527        /// Optional <see cref="AccessTier"/>
 528        /// Indicates the tier to be set on the blob.
 529        /// </param>
 530        /// <param name="progressHandler">
 531        /// Optional <see cref="IProgress{Long}"/> to provide
 532        /// progress updates about data transfers.
 533        /// </param>
 534        /// <param name="cancellationToken">
 535        /// Optional <see cref="CancellationToken"/> to propagate
 536        /// notifications that the operation should be cancelled.
 537        /// </param>
 538        /// <returns>
 539        /// A <see cref="Response{BlobContentInfo}"/> describing the
 540        /// state of the updated block blob.
 541        /// </returns>
 542        /// <remarks>
 543        /// A <see cref="RequestFailedException"/> will be thrown if
 544        /// a failure occurs.
 545        /// </remarks>
 546        [EditorBrowsable(EditorBrowsableState.Never)]
 547        public virtual Response<BlobContentInfo> Upload(
 548            Stream content,
 549            BlobHttpHeaders httpHeaders = default,
 550            Metadata metadata = default,
 551            BlobRequestConditions conditions = default,
 552            AccessTier? accessTier = default,
 553            IProgress<long> progressHandler = default,
 554            CancellationToken cancellationToken = default)
 902555            => Upload(
 902556                content,
 902557                new BlobUploadOptions
 902558                {
 902559                    HttpHeaders = httpHeaders,
 902560                    Metadata = metadata,
 902561                    Conditions = conditions,
 902562                    AccessTier = accessTier,
 902563                    ProgressHandler = progressHandler,
 902564                },
 902565                cancellationToken);
 566
 567        /// <summary>
 568        /// The <see cref="UploadAsync(Stream, BlobHttpHeaders, Metadata, BlobRequestConditions, AccessTier?, IProgress{
 569        /// operation creates a new block  blob, or updates the content of an existing block blob.  Updating an
 570        /// existing block blob overwrites any existing metadata on the blob.
 571        ///
 572        /// Partial updates are not supported with <see cref="UploadAsync(Stream, BlobHttpHeaders, Metadata, BlobRequest
 573        /// the content of the existing blob is overwritten with the content
 574        /// of the new blob.  To perform a partial update of the content of a
 575        /// block blob, use the <see cref="StageBlockAsync"/> and
 576        /// <see cref="CommitBlockListAsync(IEnumerable{string}, BlobHttpHeaders, Metadata, BlobRequestConditions, Acces
 577        ///
 578        /// For more information, see
 579        /// <see href="https://docs.microsoft.com/rest/api/storageservices/put-blob">
 580        /// Put Blob</see>.
 581        /// </summary>
 582        /// <param name="content">
 583        /// A <see cref="Stream"/> containing the content to upload.
 584        /// </param>
 585        /// <param name="httpHeaders">
 586        /// Optional standard HTTP header properties that can be set for the
 587        /// block blob.
 588        /// </param>
 589        /// <param name="metadata">
 590        /// Optional custom metadata to set for this block blob.
 591        /// </param>
 592        /// <param name="conditions">
 593        /// Optional <see cref="BlobRequestConditions"/> to add
 594        /// conditions on the creation of this new block blob.
 595        /// </param>
 596        /// <param name="accessTier">
 597        /// Optional <see cref="AccessTier"/>
 598        /// Indicates the tier to be set on the blob.
 599        /// </param>
 600        /// <param name="progressHandler">
 601        /// Optional <see cref="IProgress{Long}"/> to provide
 602        /// progress updates about data transfers.
 603        /// </param>
 604        /// <param name="cancellationToken">
 605        /// Optional <see cref="CancellationToken"/> to propagate
 606        /// notifications that the operation should be cancelled.
 607        /// </param>
 608        /// <returns>
 609        /// A <see cref="Response{BlobContentInfo}"/> describing the
 610        /// state of the updated block blob.
 611        /// </returns>
 612        /// <remarks>
 613        /// A <see cref="RequestFailedException"/> will be thrown if
 614        /// a failure occurs.
 615        /// </remarks>
 616        [EditorBrowsable(EditorBrowsableState.Never)]
 617        public virtual async Task<Response<BlobContentInfo>> UploadAsync(
 618            Stream content,
 619            BlobHttpHeaders httpHeaders = default,
 620            Metadata metadata = default,
 621            BlobRequestConditions conditions = default,
 622            AccessTier? accessTier = default,
 623            IProgress<long> progressHandler = default,
 624            CancellationToken cancellationToken = default)
 942625            => await UploadAsync(
 942626                content,
 942627                new BlobUploadOptions
 942628                {
 942629                    HttpHeaders = httpHeaders,
 942630                    Metadata = metadata,
 942631                    Conditions = conditions,
 942632                    AccessTier = accessTier,
 942633                    ProgressHandler = progressHandler,
 942634                },
 942635                cancellationToken).ConfigureAwait(false);
 636
 637        /// <summary>
 638        /// The <see cref="UploadInternal"/> operation creates a new block blob,
 639        /// or updates the content of an existing block blob.  Updating an
 640        /// existing block blob overwrites any existing metadata on the blob.
 641        ///
 642        /// Partial updates are not supported with <see cref="UploadInternal"/>;
 643        /// the content of the existing blob is overwritten with the content
 644        /// of the new blob.  To perform a partial update of the content of a
 645        /// block blob, use the <see cref="StageBlockInternal"/> and
 646        /// <see cref="CommitBlockListInternal" /> operations.
 647        ///
 648        /// For more information, see
 649        /// <see href="https://docs.microsoft.com/rest/api/storageservices/put-blob">
 650        /// Put Blob</see>.
 651        /// </summary>
 652        /// <param name="content">
 653        /// A <see cref="Stream"/> containing the content to upload.
 654        /// </param>
 655        /// <param name="blobHttpHeaders">
 656        /// Optional standard HTTP header properties that can be set for the
 657        /// block blob.
 658        /// </param>
 659        /// <param name="metadata">
 660        /// Optional custom metadata to set for this block blob.
 661        /// </param>
 662        /// <param name="tags">
 663        /// Optional tags to set for this block blob.
 664        /// </param>
 665        /// <param name="conditions">
 666        /// Optional <see cref="BlockBlobClient"/> to add
 667        /// conditions on the creation of this new block blob.
 668        /// </param>
 669        /// <param name="accessTier">
 670        /// Optional <see cref="AccessTier"/>
 671        /// Indicates the tier to be set on the blob.
 672        /// </param>
 673        /// <param name="progressHandler">
 674        /// Optional <see cref="IProgress{Long}"/> to provide
 675        /// progress updates about data transfers.
 676        /// </param>
 677        /// <param name="operationName">
 678        /// The name of the calling operation.
 679        /// </param>
 680        /// <param name="async">
 681        /// Whether to invoke the operation asynchronously.
 682        /// </param>
 683        /// <param name="cancellationToken">
 684        /// Optional <see cref="CancellationToken"/> to propagate
 685        /// notifications that the operation should be cancelled.
 686        /// </param>
 687        /// <returns>
 688        /// A <see cref="Response{BlobContentInfo}"/> describing the
 689        /// state of the updated block blob.
 690        /// </returns>
 691        /// <remarks>
 692        /// A <see cref="RequestFailedException"/> will be thrown if
 693        /// a failure occurs.
 694        /// </remarks>
 695        internal virtual async Task<Response<BlobContentInfo>> UploadInternal(
 696            Stream content,
 697            BlobHttpHeaders blobHttpHeaders,
 698            Metadata metadata,
 699            Tags tags,
 700            BlobRequestConditions conditions,
 701            AccessTier? accessTier,
 702            IProgress<long> progressHandler,
 703            string operationName,
 704            bool async,
 705            CancellationToken cancellationToken)
 706        {
 3300707            content = content?.WithNoDispose().WithProgress(progressHandler);
 3300708            using (Pipeline.BeginLoggingScope(nameof(BlockBlobClient)))
 709            {
 710                Pipeline.LogMethodEnter(
 711                    nameof(BlockBlobClient),
 712                    message:
 713                    $"{nameof(Uri)}: {Uri}\n" +
 714                    $"{nameof(blobHttpHeaders)}: {blobHttpHeaders}\n" +
 715                    $"{nameof(conditions)}: {conditions}");
 716                try
 717                {
 3300718                    return await BlobRestClient.BlockBlob.UploadAsync(
 3300719                        ClientDiagnostics,
 3300720                        Pipeline,
 3300721                        Uri,
 3300722                        body: content,
 3300723                        contentLength: content?.Length ?? 0,
 3300724                        version: Version.ToVersionString(),
 3300725                        blobContentType: blobHttpHeaders?.ContentType,
 3300726                        blobContentEncoding: blobHttpHeaders?.ContentEncoding,
 3300727                        blobContentLanguage: blobHttpHeaders?.ContentLanguage,
 3300728                        blobContentHash: blobHttpHeaders?.ContentHash,
 3300729                        blobCacheControl: blobHttpHeaders?.CacheControl,
 3300730                        metadata: metadata,
 3300731                        leaseId: conditions?.LeaseId,
 3300732                        blobContentDisposition: blobHttpHeaders?.ContentDisposition,
 3300733                        encryptionKey: CustomerProvidedKey?.EncryptionKey,
 3300734                        encryptionKeySha256: CustomerProvidedKey?.EncryptionKeyHash,
 3300735                        encryptionAlgorithm: CustomerProvidedKey?.EncryptionAlgorithm,
 3300736                        encryptionScope: EncryptionScope,
 3300737                        tier: accessTier,
 3300738                        ifModifiedSince: conditions?.IfModifiedSince,
 3300739                        ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
 3300740                        ifMatch: conditions?.IfMatch,
 3300741                        ifNoneMatch: conditions?.IfNoneMatch,
 3300742                        ifTags: conditions?.TagConditions,
 3300743                        blobTagsString: tags?.ToTagsString(),
 3300744                        async: async,
 3300745                        operationName: operationName ?? $"{nameof(BlockBlobClient)}.{nameof(Upload)}",
 3300746                        cancellationToken: cancellationToken)
 3300747                        .ConfigureAwait(false);
 748                }
 48749                catch (Exception ex)
 750                {
 751                    Pipeline.LogException(ex);
 48752                    throw;
 753                }
 754                finally
 755                {
 756                    Pipeline.LogMethodExit(nameof(BlockBlobClient));
 757                }
 758            }
 3252759        }
 760        #endregion Upload
 761
 762        #region StageBlock
 763        /// <summary>
 764        /// The <see cref="StageBlock"/> operation creates a new block as
 765        /// part of a block blob's "staging area" to be eventually committed
 766        /// via the <see cref="CommitBlockList(IEnumerable{string}, CommitBlockListOptions, CancellationToken)"/> operat
 767        ///
 768        /// For more information, see
 769        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/put-block">
 770        /// Put Block</see>.
 771        /// </summary>
 772        /// <param name="base64BlockId">
 773        /// A valid Base64 string value that identifies the block. Prior to
 774        /// encoding, the string must be less than or equal to 64 bytes in
 775        /// size.
 776        ///
 777        /// For a given blob, the length of the value specified for the
 778        /// blockid parameter must be the same size for each block. Note that
 779        /// the Base64 string must be URL-encoded.
 780        /// </param>
 781        /// <param name="content">
 782        /// A <see cref="Stream"/> containing the content to upload.
 783        /// </param>
 784        /// <param name="transactionalContentHash">
 785        /// An optional MD5 hash of the block <paramref name="content"/>.
 786        /// This hash is used to verify the integrity of the block during
 787        /// transport.  When this value is specified, the storage service
 788        /// compares the hash of the content that has arrived with this value.
 789        /// Note that this MD5 hash is not stored with the blob.  If the two
 790        /// hashes do not match, the operation will throw a
 791        /// <see cref="RequestFailedException"/>.
 792        /// </param>
 793        /// <param name="conditions">
 794        /// Optional <see cref="BlobRequestConditions"/> to add
 795        /// conditions on the upload of this block.
 796        /// </param>
 797        /// <param name="progressHandler">
 798        /// Optional <see cref="IProgress{Long}"/> to provide
 799        /// progress updates about data transfers.
 800        /// </param>
 801        /// <param name="cancellationToken">
 802        /// Optional <see cref="CancellationToken"/> to propagate
 803        /// notifications that the operation should be cancelled.
 804        /// </param>
 805        /// <returns>
 806        /// A <see cref="Response{BlockInfo}"/> describing the
 807        /// state of the updated block.
 808        /// </returns>
 809        /// <remarks>
 810        /// A <see cref="RequestFailedException"/> will be thrown if
 811        /// a failure occurs.
 812        /// </remarks>
 813        public virtual Response<BlockInfo> StageBlock(
 814            string base64BlockId,
 815            Stream content,
 816            byte[] transactionalContentHash = default,
 817            BlobRequestConditions conditions = default,
 818            IProgress<long> progressHandler = default,
 819            CancellationToken cancellationToken = default) =>
 120820            StageBlockInternal(
 120821                base64BlockId,
 120822                content,
 120823                transactionalContentHash,
 120824                conditions,
 120825                progressHandler,
 120826                false, // async
 120827                cancellationToken)
 120828                .EnsureCompleted();
 829
 830        /// <summary>
 831        /// The <see cref="StageBlockAsync"/> operation creates a new block as
 832        /// part of a block blob's "staging area" to be eventually committed
 833        /// via the <see cref="CommitBlockListAsync(IEnumerable{string}, CommitBlockListOptions, CancellationToken)"/> o
 834        ///
 835        /// For more information, see
 836        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/put-block">
 837        /// Put Block</see>.
 838        /// </summary>
 839        /// <param name="base64BlockId">
 840        /// A valid Base64 string value that identifies the block. Prior to
 841        /// encoding, the string must be less than or equal to 64 bytes in
 842        /// size.
 843        ///
 844        /// For a given blob, the length of the value specified for the
 845        /// blockid parameter must be the same size for each block. Note that
 846        /// the Base64 string must be URL-encoded.
 847        /// </param>
 848        /// <param name="content">
 849        /// A <see cref="Stream"/> containing the content to upload.
 850        /// </param>
 851        /// <param name="transactionalContentHash">
 852        /// An optional MD5 hash of the block <paramref name="content"/>.
 853        /// This hash is used to verify the integrity of the block during
 854        /// transport.  When this value is specified, the storage service
 855        /// compares the hash of the content that has arrived with this value.
 856        /// Note that this MD5 hash is not stored with the blob.  If the two
 857        /// hashes do not match, the operation will throw a
 858        /// <see cref="RequestFailedException"/>.
 859        /// </param>
 860        /// <param name="conditions">
 861        /// Optional <see cref="BlobRequestConditions"/> to add
 862        /// conditions on the upload of this block.
 863        /// </param>
 864        /// <param name="progressHandler">
 865        /// Optional <see cref="IProgress{Long}"/> to provide
 866        /// progress updates about data transfers.
 867        /// </param>
 868        /// <param name="cancellationToken">
 869        /// Optional <see cref="CancellationToken"/> to propagate
 870        /// notifications that the operation should be cancelled.
 871        /// </param>
 872        /// <returns>
 873        /// A <see cref="Response{BlockInfo}"/> describing the
 874        /// state of the updated block.
 875        /// </returns>
 876        /// <remarks>
 877        /// A <see cref="RequestFailedException"/> will be thrown if
 878        /// a failure occurs.
 879        /// </remarks>
 880        public virtual async Task<Response<BlockInfo>> StageBlockAsync(
 881            string base64BlockId,
 882            Stream content,
 883            byte[] transactionalContentHash = default,
 884            BlobRequestConditions conditions = default,
 885            IProgress<long> progressHandler = default,
 886            CancellationToken cancellationToken = default) =>
 120887            await StageBlockInternal(
 120888                base64BlockId,
 120889                content,
 120890                transactionalContentHash,
 120891                conditions,
 120892                progressHandler,
 120893                true, // async
 120894                cancellationToken)
 120895                .ConfigureAwait(false);
 896
 897        /// <summary>
 898        /// The <see cref="StageBlockInternal"/> operation creates a new block
 899        /// as part of a block blob's "staging area" to be eventually committed
 900        /// via the <see cref="CommitBlockListInternal"/> operation.
 901        ///
 902        /// For more information, see
 903        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/put-block">
 904        /// Put Block</see>.
 905        /// </summary>
 906        /// <param name="base64BlockId">
 907        /// A valid Base64 string value that identifies the block. Prior to
 908        /// encoding, the string must be less than or equal to 64 bytes in
 909        /// size.
 910        ///
 911        /// For a given blob, the length of the value specified for the
 912        /// blockid parameter must be the same size for each block. Note that
 913        /// the Base64 string must be URL-encoded.
 914        /// </param>
 915        /// <param name="content">
 916        /// A <see cref="Stream"/> containing the content to upload.
 917        /// </param>
 918        /// <param name="transactionalContentHash">
 919        /// An optional MD5 hash of the block <paramref name="content"/>.
 920        /// This hash is used to verify the integrity of the block during
 921        /// transport.  When this value is specified, the storage service
 922        /// compares the hash of the content that has arrived with this value.
 923        /// Note that this MD5 hash is not stored with the blob.  If the two
 924        /// hashes do not match, the operation will throw a
 925        /// <see cref="RequestFailedException"/>.
 926        /// </param>
 927        /// <param name="conditions">
 928        /// Optional <see cref="BlobRequestConditions"/> to add
 929        /// conditions on the upload of this block.
 930        /// </param>
 931        /// <param name="progressHandler">
 932        /// Optional <see cref="IProgress{Long}"/> to provide
 933        /// progress updates about data transfers.
 934        /// </param>
 935        /// <param name="async">
 936        /// Whether to invoke the operation asynchronously.
 937        /// </param>
 938        /// <param name="cancellationToken">
 939        /// Optional <see cref="CancellationToken"/> to propagate
 940        /// notifications that the operation should be cancelled.
 941        /// </param>
 942        /// <returns>
 943        /// A <see cref="Response{BlockInfo}"/> describing the
 944        /// state of the updated block.
 945        /// </returns>
 946        /// <remarks>
 947        /// A <see cref="RequestFailedException"/> will be thrown if
 948        /// a failure occurs.
 949        /// </remarks>
 950        internal virtual async Task<Response<BlockInfo>> StageBlockInternal(
 951            string base64BlockId,
 952            Stream content,
 953            byte[] transactionalContentHash,
 954            BlobRequestConditions conditions,
 955            IProgress<long> progressHandler,
 956            bool async,
 957            CancellationToken cancellationToken)
 958        {
 1176959            using (Pipeline.BeginLoggingScope(nameof(BlockBlobClient)))
 960            {
 961                Pipeline.LogMethodEnter(
 962                    nameof(BlockBlobClient),
 963                    message:
 964                    $"{nameof(Uri)}: {Uri}\n" +
 965                    $"{nameof(base64BlockId)}: {base64BlockId}\n" +
 966                    $"{nameof(conditions)}: {conditions}");
 967                try
 968                {
 1176969                    content = content.WithNoDispose().WithProgress(progressHandler);
 1176970                    return await BlobRestClient.BlockBlob.StageBlockAsync(
 1176971                        ClientDiagnostics,
 1176972                        Pipeline,
 1176973                        Uri,
 1176974                        blockId: base64BlockId,
 1176975                        body: content,
 1176976                        contentLength: content.Length,
 1176977                        version: Version.ToVersionString(),
 1176978                        transactionalContentHash: transactionalContentHash,
 1176979                        leaseId: conditions?.LeaseId,
 1176980                        encryptionKey: CustomerProvidedKey?.EncryptionKey,
 1176981                        encryptionKeySha256: CustomerProvidedKey?.EncryptionKeyHash,
 1176982                        encryptionAlgorithm: CustomerProvidedKey?.EncryptionAlgorithm,
 1176983                        encryptionScope: EncryptionScope,
 1176984                        async: async,
 1176985                        operationName: $"{nameof(BlockBlobClient)}.{nameof(StageBlock)}",
 1176986                        cancellationToken: cancellationToken).ConfigureAwait(false);
 987                }
 8988                catch (Exception ex)
 989                {
 990                    Pipeline.LogException(ex);
 8991                    throw;
 992                }
 993                finally
 994                {
 995                    Pipeline.LogMethodExit(nameof(BlockBlobClient));
 996                }
 997            }
 1168998        }
 999        #endregion StageBlock
 1000
 1001        #region StageBlockFromUri
 1002        /// <summary>
 1003        /// The <see cref="StageBlockFromUri"/> operation creates a new
 1004        /// block to be committed as part of a blob where the contents are
 1005        /// read from the <paramref name="sourceUri" />.
 1006        ///
 1007        /// For more information, see
 1008        /// <see href="https://docs.microsoft.com/rest/api/storageservices/put-block-from-url">
 1009        /// Put Block From URL</see>.
 1010        /// </summary>
 1011        /// <param name="sourceUri">
 1012        /// Specifies the <see cref="Uri"/> of the source blob.  The value may
 1013        /// be a URL of up to 2 KB in length that specifies a blob.  The
 1014        /// source blob must either be public or must be authenticated via a
 1015        /// shared access signature. If the source blob is public, no
 1016        /// authentication is required to perform the operation.
 1017        /// </param>
 1018        /// <param name="base64BlockId">
 1019        /// A valid Base64 string value that identifies the block. Prior to
 1020        /// encoding, the string must be less than or equal to 64 bytes in
 1021        /// size.  For a given blob, the length of the value specified for
 1022        /// the <paramref name="base64BlockId"/> parameter must be the same
 1023        /// size for each block.  Note that the Base64 string must be
 1024        /// URL-encoded.
 1025        /// </param>
 1026        /// <param name="sourceRange">
 1027        /// Optionally uploads only the bytes of the blob in the
 1028        /// <paramref name="sourceUri"/> in the specified range.  If this is
 1029        /// not specified, the entire source blob contents are uploaded as a
 1030        /// single block.
 1031        /// </param>
 1032        /// <param name="sourceContentHash">
 1033        /// Optional MD5 hash of the block content from the
 1034        /// <paramref name="sourceUri"/>.  This hash is used to verify the
 1035        /// integrity of the block during transport of the data from the Uri.
 1036        /// When this hash is specified, the storage service compares the hash
 1037        /// of the content that has arrived from the <paramref name="sourceUri"/>
 1038        /// with this value.  Note that this md5 hash is not stored with the
 1039        /// blob.  If the two hashes do not match, the operation will fail
 1040        /// with a <see cref="RequestFailedException"/>.
 1041        /// </param>
 1042        /// <param name="sourceConditions">
 1043        /// Optional <see cref="RequestConditions"/> to add
 1044        /// conditions on the copying of data from this source blob.
 1045        /// </param>
 1046        /// <param name="conditions">
 1047        /// Optional <see cref="BlobRequestConditions"/> to add
 1048        /// conditions on the staging of this block.
 1049        /// </param>
 1050        /// <param name="cancellationToken">
 1051        /// Optional <see cref="CancellationToken"/> to propagate
 1052        /// notifications that the operation should be cancelled.
 1053        /// </param>
 1054        /// <returns>
 1055        /// A <see cref="Response{BlockInfo}"/> describing the
 1056        /// state of the updated block blob.
 1057        /// </returns>
 1058        /// <remarks>
 1059        /// A <see cref="RequestFailedException"/> will be thrown if
 1060        /// a failure occurs.
 1061        /// </remarks>
 1062        public virtual Response<BlockInfo> StageBlockFromUri(
 1063            Uri sourceUri,
 1064            string base64BlockId,
 1065            HttpRange sourceRange = default,
 1066            byte[] sourceContentHash = default,
 1067            RequestConditions sourceConditions = default,
 1068            BlobRequestConditions conditions = default,
 1069            CancellationToken cancellationToken = default) =>
 361070            StageBlockFromUriInternal(
 361071                sourceUri,
 361072                base64BlockId,
 361073                sourceRange,
 361074                sourceContentHash,
 361075                sourceConditions,
 361076                conditions,
 361077                false, // async
 361078                cancellationToken)
 361079                .EnsureCompleted();
 1080
 1081        /// <summary>
 1082        /// The <see cref="StageBlockFromUriAsync"/> operation creates a new
 1083        /// block to be committed as part of a blob where the contents are
 1084        /// read from the <paramref name="sourceUri" />.
 1085        ///
 1086        /// For more information, see
 1087        /// <see href="https://docs.microsoft.com/rest/api/storageservices/put-block-from-url">
 1088        /// Put Block From URL</see>.
 1089        /// </summary>
 1090        /// <param name="sourceUri">
 1091        /// Specifies the <see cref="Uri"/> of the source blob.  The value may
 1092        /// be a URL of up to 2 KB in length that specifies a blob.  The
 1093        /// source blob must either be public or must be authenticated via a
 1094        /// shared access signature. If the source blob is public, no
 1095        /// authentication is required to perform the operation.
 1096        /// </param>
 1097        /// <param name="base64BlockId">
 1098        /// A valid Base64 string value that identifies the block. Prior to
 1099        /// encoding, the string must be less than or equal to 64 bytes in
 1100        /// size.  For a given blob, the length of the value specified for
 1101        /// the <paramref name="base64BlockId"/> parameter must be the same
 1102        /// size for each block.  Note that the Base64 string must be
 1103        /// URL-encoded.
 1104        /// </param>
 1105        /// <param name="sourceRange">
 1106        /// Optionally uploads only the bytes of the blob in the
 1107        /// <paramref name="sourceUri"/> in the specified range.  If this is
 1108        /// not specified, the entire source blob contents are uploaded as a
 1109        /// single block.
 1110        /// </param>
 1111        /// <param name="sourceContentHash">
 1112        /// Optional MD5 hash of the block content from the
 1113        /// <paramref name="sourceUri"/>.  This hash is used to verify the
 1114        /// integrity of the block during transport of the data from the Uri.
 1115        /// When this hash is specified, the storage service compares the hash
 1116        /// of the content that has arrived from the <paramref name="sourceUri"/>
 1117        /// with this value.  Note that this md5 hash is not stored with the
 1118        /// blob.  If the two hashes do not match, the operation will fail
 1119        /// with a <see cref="RequestFailedException"/>.
 1120        /// </param>
 1121        /// <param name="sourceConditions">
 1122        /// Optional <see cref="RequestConditions"/> to add
 1123        /// conditions on the copying of data from this source blob.
 1124        /// </param>
 1125        /// <param name="conditions">
 1126        /// Optional <see cref="BlobRequestConditions"/> to add
 1127        /// conditions on the staging of this block.
 1128        /// </param>
 1129        /// <param name="cancellationToken">
 1130        /// Optional <see cref="CancellationToken"/> to propagate
 1131        /// notifications that the operation should be cancelled.
 1132        /// </param>
 1133        /// <returns>
 1134        /// A <see cref="Response{BlockInfo}"/> describing the
 1135        /// state of the updated block.
 1136        /// </returns>
 1137        /// <remarks>
 1138        /// A <see cref="RequestFailedException"/> will be thrown if
 1139        /// a failure occurs.
 1140        /// </remarks>
 1141        public virtual async Task<Response<BlockInfo>> StageBlockFromUriAsync(
 1142            Uri sourceUri,
 1143            string base64BlockId,
 1144            HttpRange sourceRange = default,
 1145            byte[] sourceContentHash = default,
 1146            RequestConditions sourceConditions = default,
 1147            BlobRequestConditions conditions = default,
 1148            CancellationToken cancellationToken = default) =>
 361149            await StageBlockFromUriInternal(
 361150                sourceUri,
 361151                base64BlockId,
 361152                sourceRange,
 361153                sourceContentHash,
 361154                sourceConditions,
 361155                conditions,
 361156                true, // async
 361157                cancellationToken)
 361158                .ConfigureAwait(false);
 1159
 1160        /// <summary>
 1161        /// The <see cref="StageBlockFromUriInternal"/> operation creates a new
 1162        /// block to be committed as part of a blob where the contents are
 1163        /// read from the <paramref name="sourceUri" />.
 1164        ///
 1165        /// For more information, see
 1166        /// <see href="https://docs.microsoft.com/rest/api/storageservices/put-block-from-url">
 1167        /// Put Block From URL</see>.
 1168        /// </summary>
 1169        /// <param name="sourceUri">
 1170        /// Specifies the <see cref="Uri"/> of the source blob.  The value may
 1171        /// be a URL of up to 2 KB in length that specifies a blob.  The
 1172        /// source blob must either be public or must be authenticated via a
 1173        /// shared access signature. If the source blob is public, no
 1174        /// authentication is required to perform the operation.
 1175        /// </param>
 1176        /// <param name="base64BlockId">
 1177        /// A valid Base64 string value that identifies the block. Prior to
 1178        /// encoding, the string must be less than or equal to 64 bytes in
 1179        /// size.  For a given blob, the length of the value specified for
 1180        /// the <paramref name="base64BlockId"/> parameter must be the same
 1181        /// size for each block.  Note that the Base64 string must be
 1182        /// URL-encoded.
 1183        /// </param>
 1184        /// <param name="sourceRange">
 1185        /// Optionally uploads only the bytes of the blob in the
 1186        /// <paramref name="sourceUri"/> in the specified range.  If this is
 1187        /// not specified, the entire source blob contents are uploaded as a
 1188        /// single block.
 1189        /// </param>
 1190        /// <param name="sourceContentHash">
 1191        /// Optional MD5 hash of the block content from the
 1192        /// <paramref name="sourceUri"/>.  This hash is used to verify the
 1193        /// integrity of the block during transport of the data from the Uri.
 1194        /// When this hash is specified, the storage service compares the hash
 1195        /// of the content that has arrived from the <paramref name="sourceUri"/>
 1196        /// with this value.  Note that this md5 hash is not stored with the
 1197        /// blob.  If the two hashes do not match, the operation will fail
 1198        /// with a <see cref="RequestFailedException"/>.
 1199        /// </param>
 1200        /// <param name="sourceConditions">
 1201        /// Optional <see cref="RequestConditions"/> to add
 1202        /// conditions on the copying of data from this source blob.
 1203        /// </param>
 1204        /// <param name="conditions">
 1205        /// Optional <see cref="BlobRequestConditions"/> to add
 1206        /// conditions on the staging of this block.
 1207        /// </param>
 1208        /// <param name="async">
 1209        /// Whether to invoke the operation asynchronously.
 1210        /// </param>
 1211        /// <param name="cancellationToken">
 1212        /// Optional <see cref="CancellationToken"/> to propagate
 1213        /// notifications that the operation should be cancelled.
 1214        /// </param>
 1215        /// <returns>
 1216        /// A <see cref="Response{BlockInfo}"/> describing the
 1217        /// state of the updated block.
 1218        /// </returns>
 1219        /// <remarks>
 1220        /// A <see cref="RequestFailedException"/> will be thrown if
 1221        /// a failure occurs.
 1222        /// </remarks>
 1223        private async Task<Response<BlockInfo>> StageBlockFromUriInternal(
 1224            Uri sourceUri,
 1225            string base64BlockId,
 1226            HttpRange sourceRange,
 1227            byte[] sourceContentHash,
 1228            RequestConditions sourceConditions,
 1229            BlobRequestConditions conditions,
 1230            bool async,
 1231            CancellationToken cancellationToken)
 1232        {
 721233            using (Pipeline.BeginLoggingScope(nameof(BlockBlobClient)))
 1234            {
 1235                Pipeline.LogMethodEnter(
 1236                    nameof(BlockBlobClient),
 1237                    message:
 1238                    $"{nameof(Uri)}: {Uri}\n" +
 1239                    $"{nameof(base64BlockId)}: {base64BlockId}\n" +
 1240                    $"{nameof(sourceUri)}: {sourceUri}\n" +
 1241                    $"{nameof(conditions)}: {conditions}");
 1242                try
 1243                {
 721244                    return await BlobRestClient.BlockBlob.StageBlockFromUriAsync(
 721245                        ClientDiagnostics,
 721246                        Pipeline,
 721247                        Uri,
 721248                        contentLength: default,
 721249                        blockId: base64BlockId,
 721250                        sourceUri: sourceUri,
 721251                        version: Version.ToVersionString(),
 721252                        sourceRange: sourceRange.ToString(),
 721253                        sourceContentHash: sourceContentHash,
 721254                        encryptionKey: CustomerProvidedKey?.EncryptionKey,
 721255                        encryptionKeySha256: CustomerProvidedKey?.EncryptionKeyHash,
 721256                        encryptionAlgorithm: CustomerProvidedKey?.EncryptionAlgorithm,
 721257                        encryptionScope: EncryptionScope,
 721258                        leaseId: conditions?.LeaseId,
 721259                        sourceIfModifiedSince: sourceConditions?.IfModifiedSince,
 721260                        sourceIfUnmodifiedSince: sourceConditions?.IfUnmodifiedSince,
 721261                        sourceIfMatch: sourceConditions?.IfMatch,
 721262                        sourceIfNoneMatch: sourceConditions?.IfNoneMatch,
 721263                        async: async,
 721264                        operationName: $"{nameof(BlockBlobClient)}.{nameof(StageBlockFromUri)}",
 721265                        cancellationToken: cancellationToken)
 721266                        .ConfigureAwait(false);
 1267                }
 241268                catch (Exception ex)
 1269                {
 1270                    Pipeline.LogException(ex);
 241271                    throw;
 1272                }
 1273                finally
 1274                {
 1275                    Pipeline.LogMethodExit(nameof(BlockBlobClient));
 1276                }
 1277            }
 481278        }
 1279        #endregion StageBlockFromUri
 1280
 1281        #region CommitBlockList
 1282        /// <summary>
 1283        /// The <see cref="CommitBlockList(IEnumerable{string}, CommitBlockListOptions, CancellationToken)"/>
 1284        /// operation writes a blob by specifying the list of block IDs that make up the blob.  In order
 1285        /// to be written as part of a blob, a block must have been
 1286        /// successfully written to the server in a prior <see cref="StageBlock"/>
 1287        /// operation.  You can call <see cref="CommitBlockList(IEnumerable{string}, CommitBlockListOptions, Cancellatio
 1288        /// to update a blob by uploading only those blocks that have changed,
 1289        /// then committing the new and existing blocks together.  You can do
 1290        /// this by specifying whether to commit a block from the committed
 1291        /// block list or from the uncommitted block list, or to commit the
 1292        /// most recently uploaded version of the block, whichever list it
 1293        /// may belong to.  Any blocks not specified in the block list and
 1294        /// permanently deleted.
 1295        ///
 1296        /// For more information, see
 1297        /// <see href="https://docs.microsoft.com/rest/api/storageservices/put-block-list">
 1298        /// Put Block List</see>.
 1299        /// </summary>
 1300        /// <param name="base64BlockIds">
 1301        /// Specify the Uncommitted Base64 encoded block IDs to indicate that
 1302        /// the blob service should search only the uncommitted block list for
 1303        /// the named blocks.  If the block is not found in the uncommitted
 1304        /// block list, it will not be written as part of the blob, and a
 1305        /// <see cref="RequestFailedException"/> will be thrown.
 1306        /// </param>
 1307        /// <param name="options">
 1308        /// Optional parameters.
 1309        /// </param>
 1310        /// <param name="cancellationToken">
 1311        /// Optional <see cref="CancellationToken"/> to propagate
 1312        /// notifications that the operation should be cancelled.
 1313        /// </param>
 1314        /// <returns>
 1315        /// A <see cref="Response{BlobContentInfo}"/> describing the
 1316        /// state of the updated block blob.
 1317        /// </returns>
 1318        /// <remarks>
 1319        /// A <see cref="RequestFailedException"/> will be thrown if
 1320        /// a failure occurs.
 1321        /// </remarks>
 1322        public virtual Response<BlobContentInfo> CommitBlockList(
 1323            IEnumerable<string> base64BlockIds,
 1324            CommitBlockListOptions options,
 1325            CancellationToken cancellationToken = default) =>
 21326            CommitBlockListInternal(
 21327                base64BlockIds,
 21328                options?.HttpHeaders,
 21329                options?.Metadata,
 21330                options?.Tags,
 21331                options?.Conditions,
 21332                options?.AccessTier,
 21333                false, // async
 21334                cancellationToken)
 21335                .EnsureCompleted();
 1336
 1337        /// <summary>
 1338        /// The <see cref="CommitBlockList(IEnumerable{string}, BlobHttpHeaders, Metadata, BlobRequestConditions, Access
 1339        /// operation writes a blob by specifying the list of block IDs that make up the blob.
 1340        /// In order to be written as part of a blob, a block must have been
 1341        /// successfully written to the server in a prior <see cref="StageBlock"/>
 1342        /// operation.  You can call <see cref="CommitBlockList(IEnumerable{string}, BlobHttpHeaders, Metadata, BlobRequ
 1343        /// to update a blob by uploading only those blocks that have changed,
 1344        /// then committing the new and existing blocks together.  You can do
 1345        /// this by specifying whether to commit a block from the committed
 1346        /// block list or from the uncommitted block list, or to commit the
 1347        /// most recently uploaded version of the block, whichever list it
 1348        /// may belong to.  Any blocks not specified in the block list and
 1349        /// permanently deleted.
 1350        ///
 1351        /// For more information, see
 1352        /// <see href="https://docs.microsoft.com/rest/api/storageservices/put-block-list">
 1353        /// Put Block List</see>.
 1354        /// </summary>
 1355        /// <param name="base64BlockIds">
 1356        /// Specify the Uncommitted Base64 encoded block IDs to indicate that
 1357        /// the blob service should search only the uncommitted block list for
 1358        /// the named blocks.  If the block is not found in the uncommitted
 1359        /// block list, it will not be written as part of the blob, and a
 1360        /// <see cref="RequestFailedException"/> will be thrown.
 1361        /// </param>
 1362        /// <param name="httpHeaders">
 1363        /// Optional standard HTTP header properties that can be set for the
 1364        /// block blob.
 1365        /// </param>
 1366        /// <param name="metadata">
 1367        /// Optional custom metadata to set for this block blob.
 1368        /// </param>
 1369        /// <param name="conditions">
 1370        /// Optional <see cref="BlockBlobClient"/> to add
 1371        /// conditions on committing this block list.
 1372        /// </param>
 1373        /// <param name="accessTier">
 1374        /// Optional <see cref="AccessTier"/>
 1375        /// Indicates the tier to be set on the blob.
 1376        /// </param>
 1377        /// <param name="cancellationToken">
 1378        /// Optional <see cref="CancellationToken"/> to propagate
 1379        /// notifications that the operation should be cancelled.
 1380        /// </param>
 1381        /// <returns>
 1382        /// A <see cref="Response{BlobContentInfo}"/> describing the
 1383        /// state of the updated block blob.
 1384        /// </returns>
 1385        /// <remarks>
 1386        /// A <see cref="RequestFailedException"/> will be thrown if
 1387        /// a failure occurs.
 1388        /// </remarks>
 1389        [EditorBrowsable(EditorBrowsableState.Never)]
 1390        public virtual Response<BlobContentInfo> CommitBlockList(
 1391            IEnumerable<string> base64BlockIds,
 1392            BlobHttpHeaders httpHeaders = default,
 1393            Metadata metadata = default,
 1394            BlobRequestConditions conditions = default,
 1395            AccessTier? accessTier = default,
 1396            CancellationToken cancellationToken = default) =>
 701397            CommitBlockListInternal(
 701398                base64BlockIds,
 701399                httpHeaders,
 701400                metadata,
 701401                default,
 701402                conditions,
 701403                accessTier,
 701404                false, // async
 701405                cancellationToken)
 701406                .EnsureCompleted();
 1407
 1408        /// <summary>
 1409        /// The <see cref="CommitBlockListAsync(IEnumerable{string}, CommitBlockListOptions, CancellationToken)"/>
 1410        /// operation writes a blob by specifying the list of block IDs that make up the blob.  In order
 1411        /// to be written as part of a blob, a block must have been
 1412        /// successfully written to the server in a prior <see cref="StageBlock"/>
 1413        /// operation.  You can call <see cref="CommitBlockListAsync(IEnumerable{string}, CommitBlockListOptions, Cancel
 1414        /// to update a blob by uploading only those blocks that have changed,
 1415        /// then committing the new and existing blocks together.  You can do
 1416        /// this by specifying whether to commit a block from the committed
 1417        /// block list or from the uncommitted block list, or to commit the
 1418        /// most recently uploaded version of the block, whichever list it
 1419        /// may belong to.  Any blocks not specified in the block list and
 1420        /// permanently deleted.
 1421        ///
 1422        /// For more information, see
 1423        /// <see href="https://docs.microsoft.com/rest/api/storageservices/put-block-list">
 1424        /// Put Block List</see>.
 1425        /// </summary>
 1426        /// <param name="base64BlockIds">
 1427        /// Specify the Uncommitted Base64 encoded block IDs to indicate that
 1428        /// the blob service should search only the uncommitted block list for
 1429        /// the named blocks.  If the block is not found in the uncommitted
 1430        /// block list, it will not be written as part of the blob, and a
 1431        /// <see cref="RequestFailedException"/> will be thrown.
 1432        /// </param>
 1433        /// <param name="options">
 1434        /// Optional parameters.
 1435        /// </param>
 1436        /// <param name="cancellationToken">
 1437        /// Optional <see cref="CancellationToken"/> to propagate
 1438        /// notifications that the operation should be cancelled.
 1439        /// </param>
 1440        /// <returns>
 1441        /// A <see cref="Response{BlobContentInfo}"/> describing the
 1442        /// state of the updated block blob.
 1443        /// </returns>
 1444        /// <remarks>
 1445        /// A <see cref="RequestFailedException"/> will be thrown if
 1446        /// a failure occurs.
 1447        /// </remarks>
 1448        public virtual async Task<Response<BlobContentInfo>> CommitBlockListAsync(
 1449            IEnumerable<string> base64BlockIds,
 1450            CommitBlockListOptions options,
 1451            CancellationToken cancellationToken = default) =>
 21452            await CommitBlockListInternal(
 21453                base64BlockIds,
 21454                options?.HttpHeaders,
 21455                options?.Metadata,
 21456                options?.Tags,
 21457                options?.Conditions,
 21458                options?.AccessTier,
 21459                true, // async
 21460                cancellationToken)
 21461                .ConfigureAwait(false);
 1462
 1463        /// <summary>
 1464        /// The <see cref="CommitBlockListAsync(IEnumerable{string}, BlobHttpHeaders, Metadata, BlobRequestConditions, A
 1465        /// operation writes a blob bys pecifying the list of block IDs that make up the blob.
 1466        /// In order to be written as part of a blob, a block must have been
 1467        /// successfully written to the server in a prior <see cref="StageBlockAsync"/>
 1468        /// operation.  You can call <see cref="CommitBlockListAsync(IEnumerable{string}, BlobHttpHeaders, Metadata, Blo
 1469        /// to update a blob by uploading only those blocks that have changed,
 1470        /// then committing the new and existing blocks together.  You can do
 1471        /// this by specifying whether to commit a block from the committed
 1472        /// block list or from the uncommitted block list, or to commit the
 1473        /// most recently uploaded version of the block, whichever list it
 1474        /// may belong to.  Any blocks not specified in the block list and
 1475        /// permanently deleted.
 1476        ///
 1477        /// For more information, see
 1478        /// <see href="https://docs.microsoft.com/rest/api/storageservices/put-block-list">
 1479        /// Put Block List</see>.
 1480        /// </summary>
 1481        /// <param name="base64BlockIds">
 1482        /// Specify the Uncommitted Base64 encoded block IDs to indicate that
 1483        /// the blob service should search only the uncommitted block list for
 1484        /// the named blocks.  If the block is not found in the uncommitted
 1485        /// block list, it will not be written as part of the blob, and a
 1486        /// <see cref="RequestFailedException"/> will be thrown.
 1487        /// </param>
 1488        /// <param name="httpHeaders">
 1489        /// Optional standard HTTP header properties that can be set for the
 1490        /// block blob.
 1491        /// </param>
 1492        /// <param name="metadata">
 1493        /// Optional custom metadata to set for this block blob.
 1494        /// </param>
 1495        /// <param name="conditions">
 1496        /// Optional <see cref="BlockBlobClient"/> to add
 1497        /// conditions on committing this block list.
 1498        /// </param>
 1499        /// <param name="accessTier">
 1500        /// Optional <see cref="AccessTier"/>
 1501        /// Indicates the tier to be set on the blob.
 1502        /// </param>
 1503        /// <param name="cancellationToken">
 1504        /// Optional <see cref="CancellationToken"/> to propagate
 1505        /// notifications that the operation should be cancelled.
 1506        /// </param>
 1507        /// <returns>
 1508        /// A <see cref="Response{BlobAppendInfo}"/> describing the
 1509        /// state of the updated block blob.
 1510        /// </returns>
 1511        /// <remarks>
 1512        /// A <see cref="RequestFailedException"/> will be thrown if
 1513        /// a failure occurs.
 1514        /// </remarks>
 1515        [EditorBrowsable(EditorBrowsableState.Never)]
 1516        public virtual async Task<Response<BlobContentInfo>> CommitBlockListAsync(
 1517            IEnumerable<string> base64BlockIds,
 1518            BlobHttpHeaders httpHeaders = default,
 1519            Metadata metadata = default,
 1520            BlobRequestConditions conditions = default,
 1521            AccessTier? accessTier = default,
 1522            CancellationToken cancellationToken = default) =>
 701523            await CommitBlockListInternal(
 701524                base64BlockIds,
 701525                httpHeaders,
 701526                metadata,
 701527                default,
 701528                conditions,
 701529                accessTier,
 701530                true, // async
 701531                cancellationToken)
 701532                .ConfigureAwait(false);
 1533
 1534        /// <summary>
 1535        /// The <see cref="CommitBlockListInternal"/> operation writes a blob by
 1536        /// specifying the list of block IDs that make up the blob.  In order
 1537        /// to be written as part of a blob, a block must have been
 1538        /// successfully written to the server in a prior <see cref="StageBlockAsync"/>
 1539        /// operation.  You can call <see cref="CommitBlockListInternal"/> to
 1540        /// update a blob by uploading only those blocks that have changed,
 1541        /// then committing the new and existing blocks together.  You can do
 1542        /// this by specifying whether to commit a block from the committed
 1543        /// block list or from the uncommitted block list, or to commit the
 1544        /// most recently uploaded version of the block, whichever list it
 1545        /// may belong to.  Any blocks not specified in the block list and
 1546        /// permanently deleted.
 1547        ///
 1548        /// For more information, see
 1549        /// <see href="https://docs.microsoft.com/rest/api/storageservices/put-block-list">
 1550        /// Put Block List</see>.
 1551        /// </summary>
 1552        /// <param name="base64BlockIds">
 1553        /// Specify the Uncommitted Base64 encoded block IDs to indicate that
 1554        /// the blob service should search only the uncommitted block list for
 1555        /// the named blocks.  If the block is not found in the uncommitted
 1556        /// block list, it will not be written as part of the blob, and a
 1557        /// <see cref="RequestFailedException"/> will be thrown.
 1558        /// </param>
 1559        /// <param name="blobHttpHeaders">
 1560        /// Optional standard HTTP header properties that can be set for the
 1561        /// block blob.
 1562        /// </param>
 1563        /// <param name="metadata">
 1564        /// Optional custom metadata to set for this block blob.
 1565        /// </param>
 1566        /// <param name="tags">
 1567        /// Optional tags to set for this block blob.
 1568        /// </param>
 1569        /// <param name="conditions">
 1570        /// Optional <see cref="BlockBlobClient"/> to add
 1571        /// conditions on committing this block list.
 1572        /// </param>
 1573        /// <param name="accessTier">
 1574        /// Optional <see cref="AccessTier"/>
 1575        /// Indicates the tier to be set on the blob.
 1576        /// </param>
 1577        /// <param name="async">
 1578        /// Whether to invoke the operation asynchronously.
 1579        /// </param>
 1580        /// <param name="cancellationToken">
 1581        /// Optional <see cref="CancellationToken"/> to propagate
 1582        /// notifications that the operation should be cancelled.
 1583        /// </param>
 1584        /// <returns>
 1585        /// A <see cref="Response{BlobAppendInfo}"/> describing the
 1586        /// state of the updated block blob.
 1587        /// </returns>
 1588        /// <remarks>
 1589        /// A <see cref="RequestFailedException"/> will be thrown if
 1590        /// a failure occurs.
 1591        /// </remarks>
 1592        internal virtual async Task<Response<BlobContentInfo>> CommitBlockListInternal(
 1593            IEnumerable<string> base64BlockIds,
 1594            BlobHttpHeaders blobHttpHeaders,
 1595            Metadata metadata,
 1596            Tags tags,
 1597            BlobRequestConditions conditions,
 1598            AccessTier? accessTier,
 1599            bool async,
 1600            CancellationToken cancellationToken)
 1601        {
 2001602            using (Pipeline.BeginLoggingScope(nameof(BlockBlobClient)))
 1603            {
 1604                Pipeline.LogMethodEnter(
 1605                    nameof(BlockBlobClient),
 1606                    message:
 1607                    $"{nameof(Uri)}: {Uri}\n" +
 1608                    $"{nameof(base64BlockIds)}: {base64BlockIds}\n" +
 1609                    $"{nameof(blobHttpHeaders)}: {blobHttpHeaders}\n" +
 1610                    $"{nameof(conditions)}: {conditions}");
 1611                try
 1612                {
 2001613                    var blocks = new BlockLookupList() { Latest = base64BlockIds.ToList() };
 2001614                    return await BlobRestClient.BlockBlob.CommitBlockListAsync(
 2001615                        ClientDiagnostics,
 2001616                        Pipeline,
 2001617                        Uri,
 2001618                        blocks,
 2001619                        version: Version.ToVersionString(),
 2001620                        blobCacheControl: blobHttpHeaders?.CacheControl,
 2001621                        blobContentType: blobHttpHeaders?.ContentType,
 2001622                        blobContentEncoding: blobHttpHeaders?.ContentEncoding,
 2001623                        blobContentLanguage: blobHttpHeaders?.ContentLanguage,
 2001624                        blobContentHash: blobHttpHeaders?.ContentHash,
 2001625                        metadata: metadata,
 2001626                        leaseId: conditions?.LeaseId,
 2001627                        blobContentDisposition: blobHttpHeaders?.ContentDisposition,
 2001628                        encryptionKey: CustomerProvidedKey?.EncryptionKey,
 2001629                        encryptionKeySha256: CustomerProvidedKey?.EncryptionKeyHash,
 2001630                        encryptionAlgorithm: CustomerProvidedKey?.EncryptionAlgorithm,
 2001631                        encryptionScope: EncryptionScope,
 2001632                        tier: accessTier,
 2001633                        ifModifiedSince: conditions?.IfModifiedSince,
 2001634                        ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
 2001635                        ifMatch: conditions?.IfMatch,
 2001636                        ifNoneMatch: conditions?.IfNoneMatch,
 2001637                        ifTags: conditions?.TagConditions,
 2001638                        blobTagsString: tags?.ToTagsString(),
 2001639                        async: async,
 2001640                        operationName: $"{nameof(BlockBlobClient)}.{nameof(CommitBlockList)}",
 2001641                        cancellationToken: cancellationToken)
 2001642                        .ConfigureAwait(false);
 1643                }
 321644                catch (Exception ex)
 1645                {
 1646                    Pipeline.LogException(ex);
 321647                    throw;
 1648                }
 1649                finally
 1650                {
 1651                    Pipeline.LogMethodExit(nameof(BlockBlobClient));
 1652                }
 1653            }
 1681654        }
 1655        #endregion CommitBlockList
 1656
 1657        #region GetBlockList
 1658        /// <summary>
 1659        /// The <see cref="GetBlockList"/> operation operation retrieves
 1660        /// the list of blocks that have been uploaded as part of a block blob.
 1661        /// There are two block lists maintained for a blob.  The Committed
 1662        /// Block list has blocks that have been successfully committed to a
 1663        /// given blob with <see cref="CommitBlockList(IEnumerable{string}, CommitBlockListOptions, CancellationToken)"/
 1664        /// The Uncommitted Block list has blocks that have been uploaded for a
 1665        /// blob using <see cref="StageBlock"/>, but that have not yet
 1666        /// been committed.  These blocks are stored in Azure in association
 1667        /// with a blob, but do not yet form part of the blob.
 1668        /// </summary>
 1669        /// <param name="blockListTypes">
 1670        /// Specifies whether to return the list of committed blocks, the
 1671        /// list of uncommitted blocks, or both lists together.  If you omit
 1672        /// this parameter, Get Block List returns the list of committed blocks.
 1673        /// </param>
 1674        /// <param name="snapshot">
 1675        /// Optionally specifies the blob snapshot to retrieve the block list
 1676        /// from. For more information on working with blob snapshots, see
 1677        /// <see href="https://docs.microsoft.com/rest/api/storageservices/creating-a-snapshot-of-a-blob">
 1678        /// Create a snapshot of a blob</see>.
 1679        /// </param>
 1680        /// <param name="conditions">
 1681        /// Optional <see cref="BlobRequestConditions"/> to add
 1682        /// conditions on retrieving the block list.
 1683        /// </param>
 1684        /// <param name="cancellationToken">
 1685        /// Optional <see cref="CancellationToken"/> to propagate
 1686        /// notifications that the operation should be cancelled.
 1687        /// </param>
 1688        /// <returns>
 1689        /// A <see cref="Response{BlockList}"/> describing requested
 1690        /// block list.
 1691        /// </returns>
 1692        /// <remarks>
 1693        /// A <see cref="RequestFailedException"/> will be thrown if
 1694        /// a failure occurs.
 1695        /// </remarks>
 1696        public virtual Response<BlockList> GetBlockList(
 1697            BlockListTypes blockListTypes = BlockListTypes.All,
 1698            string snapshot = default,
 1699            BlobRequestConditions conditions = default,
 1700            CancellationToken cancellationToken = default) =>
 341701            GetBlockListInternal(
 341702                blockListTypes,
 341703                snapshot,
 341704                conditions,
 341705                false, // async
 341706                cancellationToken)
 341707                .EnsureCompleted();
 1708
 1709        /// <summary>
 1710        /// The <see cref="GetBlockListAsync"/> operation operation retrieves
 1711        /// the list of blocks that have been uploaded as part of a block blob.
 1712        /// There are two block lists maintained for a blob.  The Committed
 1713        /// Block list has blocks that have been successfully committed to a
 1714        /// given blob with <see cref="CommitBlockListAsync(IEnumerable{string}, CommitBlockListOptions, CancellationTok
 1715        /// The Uncommitted Block list has blocks that have been uploaded for a
 1716        /// blob using <see cref="StageBlockAsync"/>, but that have not yet
 1717        /// been committed.  These blocks are stored in Azure in association
 1718        /// with a blob, but do not yet form part of the blob.
 1719        /// </summary>
 1720        /// <param name="blockListTypes">
 1721        /// Specifies whether to return the list of committed blocks, the
 1722        /// list of uncommitted blocks, or both lists together.  If you omit
 1723        /// this parameter, Get Block List returns the list of committed blocks.
 1724        /// </param>
 1725        /// <param name="snapshot">
 1726        /// Optionally specifies the blob snapshot to retrieve the block list
 1727        /// from. For more information on working with blob snapshots, see
 1728        /// <see href="https://docs.microsoft.com/rest/api/storageservices/creating-a-snapshot-of-a-blob">
 1729        /// Create a snapshot of a blob</see>.
 1730        /// </param>
 1731        /// <param name="conditions">
 1732        /// Optional <see cref="BlobRequestConditions"/> to add
 1733        /// conditions on retrieving the block list.
 1734        /// </param>
 1735        /// <param name="cancellationToken">
 1736        /// Optional <see cref="CancellationToken"/> to propagate
 1737        /// notifications that the operation should be cancelled.
 1738        /// </param>
 1739        /// <returns>
 1740        /// A <see cref="Response{BlockList}"/> describing requested
 1741        /// block list.
 1742        /// </returns>
 1743        /// <remarks>
 1744        /// A <see cref="RequestFailedException"/> will be thrown if
 1745        /// a failure occurs.
 1746        /// </remarks>
 1747        public virtual async Task<Response<BlockList>> GetBlockListAsync(
 1748            BlockListTypes blockListTypes = BlockListTypes.All,
 1749            string snapshot = default,
 1750            BlobRequestConditions conditions = default,
 1751            CancellationToken cancellationToken = default) =>
 341752            await GetBlockListInternal(
 341753                blockListTypes,
 341754                snapshot,
 341755                conditions,
 341756                true, // async
 341757                cancellationToken)
 341758                .ConfigureAwait(false);
 1759
 1760        /// <summary>
 1761        /// The <see cref="GetBlockListInternal"/> operation operation retrieves
 1762        /// the list of blocks that have been uploaded as part of a block blob.
 1763        /// There are two block lists maintained for a blob.  The Committed
 1764        /// Block list has blocks that have been successfully committed to a
 1765        /// given blob with <see cref="CommitBlockListInternal"/>.  The
 1766        /// Uncommitted Block list has blocks that have been uploaded for a
 1767        /// blob using <see cref="StageBlockAsync"/>, but that have not yet
 1768        /// been committed.  These blocks are stored in Azure in association
 1769        /// with a blob, but do not yet form part of the blob.
 1770        /// </summary>
 1771        /// <param name="blockListTypes">
 1772        /// Specifies whether to return the list of committed blocks, the
 1773        /// list of uncommitted blocks, or both lists together.  If you omit
 1774        /// this parameter, Get Block List returns the list of committed blocks.
 1775        /// </param>
 1776        /// <param name="snapshot">
 1777        /// Optionally specifies the blob snapshot to retrieve the block list
 1778        /// from. For more information on working with blob snapshots, see
 1779        /// <see href="https://docs.microsoft.com/rest/api/storageservices/creating-a-snapshot-of-a-blob">
 1780        /// Create a snapshot of a blob</see>.
 1781        /// </param>
 1782        /// <param name="conditions">
 1783        /// Optional <see cref="BlobRequestConditions"/> to add
 1784        /// conditions on retrieving the block list.
 1785        /// </param>
 1786        /// <param name="async">
 1787        /// Whether to invoke the operation asynchronously.
 1788        /// </param>
 1789        /// <param name="cancellationToken">
 1790        /// Optional <see cref="CancellationToken"/> to propagate
 1791        /// notifications that the operation should be cancelled.
 1792        /// </param>
 1793        /// <returns>
 1794        /// A <see cref="Response{BlockList}"/> describing requested
 1795        /// block list.
 1796        /// </returns>
 1797        /// <remarks>
 1798        /// A <see cref="RequestFailedException"/> will be thrown if
 1799        /// a failure occurs.
 1800        /// </remarks>
 1801        private async Task<Response<BlockList>> GetBlockListInternal(
 1802            BlockListTypes blockListTypes,
 1803            string snapshot,
 1804            BlobRequestConditions conditions,
 1805            bool async,
 1806            CancellationToken cancellationToken)
 1807        {
 681808            using (Pipeline.BeginLoggingScope(nameof(BlockBlobClient)))
 1809            {
 1810                Pipeline.LogMethodEnter(
 1811                    nameof(BlockBlobClient),
 1812                    message:
 1813                    $"{nameof(Uri)}: {Uri}\n" +
 1814                    $"{nameof(blockListTypes)}: {blockListTypes}\n" +
 1815                    $"{nameof(snapshot)}: {snapshot}\n" +
 1816                    $"{nameof(conditions)}: {conditions}");
 1817                try
 1818                {
 681819                    return (await BlobRestClient.BlockBlob.GetBlockListAsync(
 681820                        ClientDiagnostics,
 681821                        Pipeline,
 681822                        Uri,
 681823                        listType: blockListTypes.ToBlockListType(),
 681824                        version: Version.ToVersionString(),
 681825                        snapshot: snapshot,
 681826                        leaseId: conditions?.LeaseId,
 681827                        ifTags: conditions?.TagConditions,
 681828                        async: async,
 681829                        operationName: $"{nameof(BlockBlobClient)}.{nameof(GetBlockList)}",
 681830                        cancellationToken: cancellationToken)
 681831                        .ConfigureAwait(false))
 681832                        .ToBlockList();
 1833                }
 121834                catch (Exception ex)
 1835                {
 1836                    Pipeline.LogException(ex);
 121837                    throw;
 1838                }
 1839                finally
 1840                {
 1841                    Pipeline.LogMethodExit(nameof(BlockBlobClient));
 1842                }
 1843            }
 561844        }
 1845        #endregion GetBlockList
 1846
 1847        #region Query
 1848        /// <summary>
 1849        /// The <see cref="Query"/> API returns the
 1850        /// result of a query against the blob.
 1851        ///
 1852        /// For more information, see
 1853        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/query-blob-contents">
 1854        /// Query Blob Contents</see>.
 1855        /// </summary>
 1856        /// <param name="querySqlExpression">
 1857        /// The query.
 1858        /// </param>
 1859        /// <param name="options">
 1860        /// Optional parameters.
 1861        /// </param>
 1862        /// <param name="cancellationToken">
 1863        /// Optional <see cref="CancellationToken"/> to propagate
 1864        /// notifications that the operation should be cancelled.
 1865        /// </param>
 1866        /// <remarks>
 1867        /// A <see cref="RequestFailedException"/> will be thrown if
 1868        /// a failure occurs.
 1869        /// </remarks>
 1870        /// <returns>
 1871        /// A <see cref="Response{BlobDownloadInfo}"/>.
 1872        /// </returns>
 1873        public virtual Response<BlobDownloadInfo> Query(
 1874            string querySqlExpression,
 1875            BlobQueryOptions options = default,
 1876            CancellationToken cancellationToken = default) =>
 701877            QueryInternal(
 701878                querySqlExpression,
 701879                options,
 701880                async: false,
 701881                cancellationToken)
 701882            .EnsureCompleted();
 1883
 1884        /// <summary>
 1885        /// The <see cref="QueryAsync"/> API returns the
 1886        /// result of a query against the blob.
 1887        ///
 1888        /// For more information, see
 1889        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/query-blob-contents">
 1890        /// Query Blob Contents</see>.
 1891        /// </summary>
 1892        /// <param name="querySqlExpression">
 1893        /// The query.
 1894        /// </param>
 1895        /// <param name="options">
 1896        /// Optional parameters.
 1897        /// </param>
 1898        /// <param name="cancellationToken">
 1899        /// Optional <see cref="CancellationToken"/> to propagate
 1900        /// notifications that the operation should be cancelled.
 1901        /// </param>
 1902        /// <remarks>
 1903        /// A <see cref="RequestFailedException"/> will be thrown if
 1904        /// a failure occurs.
 1905        /// </remarks>
 1906        /// <returns>
 1907        /// A <see cref="Response{BlobDownloadInfo}"/>.
 1908        /// </returns>
 1909        public virtual async Task<Response<BlobDownloadInfo>> QueryAsync(
 1910            string querySqlExpression,
 1911            BlobQueryOptions options = default,
 1912            CancellationToken cancellationToken = default) =>
 701913            await QueryInternal(
 701914                querySqlExpression,
 701915                options,
 701916                async: true,
 701917                cancellationToken)
 701918            .ConfigureAwait(false);
 1919
 1920        /// <summary>
 1921        /// The <see cref="QueryInternal"/> API returns the
 1922        /// result of a query against the blob.
 1923        ///
 1924        /// For more information, see
 1925        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/query-blob-contents">
 1926        /// Query Blob Contents</see>.
 1927        /// </summary>
 1928        /// <param name="querySqlExpression">
 1929        /// The query.
 1930        /// </param>
 1931        /// <param name="options">
 1932        /// Optional parameters.
 1933        /// </param>
 1934        /// <param name="async">
 1935        /// Whether to invoke the operation asynchronously.
 1936        /// </param>
 1937        /// <param name="cancellationToken">
 1938        /// Optional <see cref="CancellationToken"/> to propagate
 1939        /// notifications that the operation should be cancelled.
 1940        /// </param>
 1941        /// <remarks>
 1942        /// A <see cref="RequestFailedException"/> will be thrown if
 1943        /// a failure occurs.
 1944        /// </remarks>
 1945        /// <returns>
 1946        /// A <see cref="Response{BlobDownloadInfo}"/>.
 1947        /// </returns>
 1948        private async Task<Response<BlobDownloadInfo>> QueryInternal(
 1949            string querySqlExpression,
 1950            BlobQueryOptions options,
 1951            bool async,
 1952            CancellationToken cancellationToken)
 1953        {
 1401954            using (Pipeline.BeginLoggingScope(nameof(BlockBlobClient)))
 1955            {
 1956                Pipeline.LogMethodEnter(nameof(BlockBlobClient), message: $"{nameof(Uri)}: {Uri}");
 1957
 1958                try
 1959                {
 1401960                    QueryRequest queryRequest = new QueryRequest()
 1401961                    {
 1401962                        QueryType = Constants.QuickQuery.SqlQueryType,
 1401963                        Expression = querySqlExpression,
 1401964                        InputSerialization = options?.InputTextConfiguration.ToQuickQuerySerialization(),
 1401965                        OutputSerialization = options?.OutputTextConfiguration.ToQuickQuerySerialization()
 1401966                    };
 1401967                    (Response<BlobQueryResult> result, Stream stream) = await BlobRestClient.Blob.QueryAsync(
 1401968                        clientDiagnostics: ClientDiagnostics,
 1401969                        pipeline: Pipeline,
 1401970                        resourceUri: Uri,
 1401971                        version: Version.ToVersionString(),
 1401972                        queryRequest: queryRequest,
 1401973                        leaseId: options?.Conditions?.LeaseId,
 1401974                        encryptionKey: CustomerProvidedKey?.EncryptionKey,
 1401975                        encryptionKeySha256: CustomerProvidedKey?.EncryptionKeyHash,
 1401976                        encryptionAlgorithm: CustomerProvidedKey?.EncryptionAlgorithm,
 1401977                        ifModifiedSince: options?.Conditions?.IfModifiedSince,
 1401978                        ifUnmodifiedSince: options?.Conditions?.IfUnmodifiedSince,
 1401979                        ifMatch: options?.Conditions?.IfMatch,
 1401980                        ifNoneMatch: options?.Conditions?.IfNoneMatch,
 1401981                        ifTags: options?.Conditions?.TagConditions,
 1401982                        async: async,
 1401983                        operationName: $"{nameof(BlockBlobClient)}.{nameof(Query)}",
 1401984                        cancellationToken: cancellationToken)
 1401985                        .ConfigureAwait(false);
 1986
 881987                    Action<BlobQueryError> errorHandler = options?._errorHandler;
 881988                    Stream parsedStream = new BlobQuickQueryStream(stream, options?.ProgressHandler, errorHandler);
 881989                    result.Value.Body = parsedStream;
 1990
 881991                    return Response.FromValue(result.Value.ToBlobDownloadInfo(), result.GetRawResponse());
 1992                }
 521993                catch (Exception ex)
 1994                {
 1995                    Pipeline.LogException(ex);
 521996                    throw;
 1997                }
 1998                finally
 1999                {
 2000                    Pipeline.LogMethodExit(nameof(BlockBlobClient));
 2001                }
 2002            }
 882003        }
 2004        #endregion Query
 2005
 2006        #region PartitionedUploader
 2007        internal PartitionedUploader<BlobUploadOptions, BlobContentInfo> GetPartitionedUploader(
 2008            StorageTransferOptions transferOptions,
 2009            ArrayPool<byte> arrayPool = null,
 2010            string operationName = null)
 33642011            =>  new PartitionedUploader<BlobUploadOptions, BlobContentInfo>(
 33642012                GetPartitionedUploaderBehaviors(this),
 33642013                transferOptions,
 33642014                arrayPool,
 33642015                operationName);
 2016
 2017        internal static PartitionedUploader<BlobUploadOptions, BlobContentInfo>.Behaviors GetPartitionedUploaderBehavior
 2018        {
 2019            static string GenerateBlockId(long offset)
 2020            {
 2021                // TODO #8162 - Add in a random GUID so multiple simultaneous
 2022                // uploads won't stomp on each other and the first to commit wins.
 2023                // This will require some changes to our test framework's
 2024                // RecordedClientRequestIdPolicy.
 22882025                byte[] id = new byte[48]; // 48 raw bytes => 64 byte string once Base64 encoded
 22882026                BitConverter.GetBytes(offset).CopyTo(id, 0);
 22882027                return Convert.ToBase64String(id);
 2028            }
 2029
 34002030            return new PartitionedUploader<BlobUploadOptions, BlobContentInfo>.Behaviors
 34002031            {
 34002032                SingleUpload = async (stream, args, progressHandler, operationName, async, cancellationToken)
 67042033                    => await client.UploadInternal(
 67042034                        stream,
 67042035                        args.HttpHeaders,
 67042036                        args.Metadata,
 67042037                        args.Tags,
 67042038                        args.Conditions,
 67042039                        args.AccessTier,
 67042040                        progressHandler,
 67042041                        operationName,
 67042042                        async,
 67042043                        cancellationToken).ConfigureAwait(false),
 34002044                UploadPartition = async (stream, offset, args, progressHandler, async, cancellationToken)
 33362045                    => await client.StageBlockInternal(
 33362046                        GenerateBlockId(offset),
 33362047                        stream,
 33362048                        transactionalContentHash: default,
 33362049                        args.Conditions,
 33362050                        progressHandler,
 33362051                        async,
 33362052                        cancellationToken).ConfigureAwait(false),
 34002053                CommitPartitionedUpload = async (partitions, args, async, cancellationToken)
 22802054                    => await client.CommitBlockListInternal(
 34242055                        partitions.Select(partition => GenerateBlockId(partition.Offset)),
 22802056                        args.HttpHeaders,
 22802057                        args.Metadata,
 22802058                        args.Tags,
 22802059                        args.Conditions,
 22802060                        args.AccessTier,
 22802061                        async,
 22802062                        cancellationToken).ConfigureAwait(false),
 22802063                Scope = operationName => client.ClientDiagnostics.CreateScope(operationName
 22802064                    ?? $"{nameof(Azure)}.{nameof(Storage)}.{nameof(Blobs)}.{nameof(BlobClient)}.{nameof(BlobClient.Uploa
 34002065            };
 2066        }
 2067        #endregion
 2068    }
 2069
 2070    /// <summary>
 2071    /// Add easy to discover methods to <see cref="BlobContainerClient"/> for
 2072    /// creating <see cref="BlockBlobClient"/> instances.
 2073    /// </summary>
 2074    public static partial class SpecializedBlobExtensions
 2075    {
 2076        /// <summary>
 2077        /// Create a new <see cref="BlockBlobClient"/> object by
 2078        /// concatenating <paramref name="blobName"/> to
 2079        /// the end of the <paramref name="client"/>'s
 2080        /// <see cref="BlobContainerClient.Uri"/>. The new
 2081        /// <see cref="BlockBlobClient"/>
 2082        /// uses the same request policy pipeline as the
 2083        /// <see cref="BlobContainerClient"/>.
 2084        /// </summary>
 2085        /// <param name="client">The <see cref="BlobContainerClient"/>.</param>
 2086        /// <param name="blobName">The name of the block blob.</param>
 2087        /// <returns>A new <see cref="BlockBlobClient"/> instance.</returns>
 2088        public static BlockBlobClient GetBlockBlobClient(
 2089            this BlobContainerClient client,
 2090            string blobName)
 2091        {
 2092            if (client.ClientSideEncryption != default)
 2093            {
 2094                throw Errors.ClientSideEncryption.TypeNotSupported(typeof(BlockBlobClient));
 2095            }
 2096
 2097            BlobUriBuilder blobUriBuilder = new BlobUriBuilder(client.Uri)
 2098            {
 2099                BlobName = blobName
 2100            };
 2101
 2102            return new BlockBlobClient(
 2103                blobUriBuilder.ToUri(),
 2104                client.Pipeline,
 2105                client.Version,
 2106                client.ClientDiagnostics,
 2107                client.CustomerProvidedKey,
 2108                client.EncryptionScope);
 2109        }
 2110    }
 2111}