< Summary

Class:Azure.Storage.Blobs.Specialized.SpecializedBlobExtensions
Assembly:Azure.Storage.Blobs
File(s):C:\Git\azure-sdk-for-net\sdk\storage\Azure.Storage.Blobs\src\AppendBlobClient.cs
C:\Git\azure-sdk-for-net\sdk\storage\Azure.Storage.Blobs\src\BlobBaseClient.cs
C:\Git\azure-sdk-for-net\sdk\storage\Azure.Storage.Blobs\src\BlobLeaseClient.cs
C:\Git\azure-sdk-for-net\sdk\storage\Azure.Storage.Blobs\src\BlockBlobClient.cs
C:\Git\azure-sdk-for-net\sdk\storage\Azure.Storage.Blobs\src\PageBlobClient.cs
Covered lines:46
Uncovered lines:11
Coverable lines:57
Total lines:11769
Line coverage:80.7% (46 of 57)
Covered branches:3
Total branches:6
Branch coverage:50% (3 of 6)

Metrics

MethodCyclomatic complexity Line coverage Branch coverage
GetAppendBlobClient(...)-92.31%50%
GetBlobBaseClient(...)-100%100%
WithClientSideEncryptionOptions(...)-0%100%
GetBlobLeaseClient(...)-100%100%
GetBlobLeaseClient(...)-100%100%
GetBlockBlobClient(...)-92.31%50%
GetPageBlobClient(...)-92.31%50%

File(s)

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

#LineLine coverage
 1// Copyright (c) Microsoft Corporation. All rights reserved.
 2// Licensed under the MIT License.
 3
 4using System;
 5using System.ComponentModel;
 6using System.IO;
 7using System.Threading;
 8using System.Threading.Tasks;
 9using Azure.Core;
 10using Azure.Core.Pipeline;
 11using Azure.Storage.Blobs.Models;
 12using Azure.Storage.Shared;
 13using Metadata = System.Collections.Generic.IDictionary<string, string>;
 14using Tags = System.Collections.Generic.IDictionary<string, string>;
 15
 16#pragma warning disable SA1402  // File may only contain a single type
 17
 18namespace Azure.Storage.Blobs.Specialized
 19{
 20    /// <summary>
 21    /// The <see cref="AppendBlobClient"/> allows you to manipulate Azure
 22    /// Storage append blobs.
 23    ///
 24    /// An append blob is comprised of blocks and is optimized for append
 25    /// operations.  When you modify an append blob, blocks are added to the
 26    /// end of the blob only, via the <see cref="AppendBlockAsync"/>
 27    /// operation.  Updating or deleting of existing blocks is not supported.
 28    /// Unlike a block blob, an append blob does not expose its block IDs.
 29    ///
 30    /// Each block in an append blob can be a different size, up to a maximum
 31    /// of 4 MB, and an append blob can include up to 50,000 blocks.  The
 32    /// maximum size of an append blob is therefore slightly more than 195 GB
 33    /// (4 MB X 50,000 blocks).
 34    /// </summary>
 35    public class AppendBlobClient : BlobBaseClient
 36    {
 37        /// <summary>
 38        /// Gets the maximum number of bytes that can be sent in a call
 39        /// to AppendBlock.
 40        /// </summary>
 41        public virtual int AppendBlobMaxAppendBlockBytes => Constants.Blob.Append.MaxAppendBlockBytes;
 42
 43        /// <summary>
 44        /// Gets the maximum number of blocks allowed in an append blob.
 45        /// </summary>
 46        public virtual int AppendBlobMaxBlocks => Constants.Blob.Append.MaxBlocks;
 47
 48        #region ctors
 49        /// <summary>
 50        /// Initializes a new instance of the <see cref="AppendBlobClient"/>
 51        /// class for mocking.
 52        /// </summary>
 53        protected AppendBlobClient()
 54        {
 55        }
 56
 57        /// <summary>
 58        /// Initializes a new instance of the <see cref="AppendBlobClient"/>
 59        /// class.
 60        /// </summary>
 61        /// <param name="connectionString">
 62        /// A connection string includes the authentication information
 63        /// required for your application to access data in an Azure Storage
 64        /// account at runtime.
 65        ///
 66        /// For more information, <see href="https://docs.microsoft.com/azure/storage/common/storage-configure-connectio
 67        /// </param>
 68        /// <param name="blobContainerName">
 69        /// The name of the container containing this append blob.
 70        /// </param>
 71        /// <param name="blobName">
 72        /// The name of this append blob.
 73        /// </param>
 74        public AppendBlobClient(string connectionString, string blobContainerName, string blobName)
 75            : base(connectionString, blobContainerName, blobName)
 76        {
 77        }
 78
 79        /// <summary>
 80        /// Initializes a new instance of the <see cref="AppendBlobClient"/>
 81        /// class.
 82        /// </summary>
 83        /// <param name="connectionString">
 84        /// A connection string includes the authentication information
 85        /// required for your application to access data in an Azure Storage
 86        /// account at runtime.
 87        ///
 88        /// For more information, <see href="https://docs.microsoft.com/azure/storage/common/storage-configure-connectio
 89        /// </param>
 90        /// <param name="blobContainerName">
 91        /// The name of the container containing this append blob.
 92        /// </param>
 93        /// <param name="blobName">
 94        /// The name of this append blob.
 95        /// </param>
 96        /// <param name="options">
 97        /// Optional client options that define the transport pipeline
 98        /// policies for authentication, retries, etc., that are applied to
 99        /// every request.
 100        /// </param>
 101        public AppendBlobClient(string connectionString, string blobContainerName, string blobName, BlobClientOptions op
 102            : base(connectionString, blobContainerName, blobName, options)
 103        {
 104            AssertNoClientSideEncryption(options);
 105        }
 106
 107        /// <summary>
 108        /// Initializes a new instance of the <see cref="AppendBlobClient"/>
 109        /// class.
 110        /// </summary>
 111        /// <param name="blobUri">
 112        /// A <see cref="Uri"/> referencing the append blob that includes the
 113        /// name of the account, the name of the container, and the name of
 114        /// the blob.
 115        /// This is likely to be similar to "https://{account_name}.blob.core.windows.net/{container_name}/{blob_name}".
 116        /// </param>
 117        /// <param name="options">
 118        /// Optional client options that define the transport pipeline
 119        /// policies for authentication, retries, etc., that are applied to
 120        /// every request.
 121        /// </param>
 122        public AppendBlobClient(Uri blobUri, BlobClientOptions options = default)
 123            : base(blobUri, options)
 124        {
 125            AssertNoClientSideEncryption(options);
 126        }
 127
 128        /// <summary>
 129        /// Initializes a new instance of the <see cref="AppendBlobClient"/>
 130        /// class.
 131        /// </summary>
 132        /// <param name="blobUri">
 133        /// A <see cref="Uri"/> referencing the append blob that includes the
 134        /// name of the account, the name of the container, and the name of
 135        /// the blob.
 136        /// This is likely to be similar to "https://{account_name}.blob.core.windows.net/{container_name}/{blob_name}".
 137        /// </param>
 138        /// <param name="credential">
 139        /// The shared key credential used to sign requests.
 140        /// </param>
 141        /// <param name="options">
 142        /// Optional client options that define the transport pipeline
 143        /// policies for authentication, retries, etc., that are applied to
 144        /// every request.
 145        /// </param>
 146        public AppendBlobClient(Uri blobUri, StorageSharedKeyCredential credential, BlobClientOptions options = default)
 147            : base(blobUri, credential, options)
 148        {
 149            AssertNoClientSideEncryption(options);
 150        }
 151
 152        /// <summary>
 153        /// Initializes a new instance of the <see cref="AppendBlobClient"/>
 154        /// class.
 155        /// </summary>
 156        /// <param name="blobUri">
 157        /// A <see cref="Uri"/> referencing the append blob that includes the
 158        /// name of the account, the name of the container, and the name of
 159        /// the blob.
 160        /// This is likely to be similar to "https://{account_name}.blob.core.windows.net/{container_name}/{blob_name}".
 161        /// </param>
 162        /// <param name="credential">
 163        /// The token credential used to sign requests.
 164        /// </param>
 165        /// <param name="options">
 166        /// Optional client options that define the transport pipeline
 167        /// policies for authentication, retries, etc., that are applied to
 168        /// every request.
 169        /// </param>
 170        public AppendBlobClient(Uri blobUri, TokenCredential credential, BlobClientOptions options = default)
 171            : base(blobUri, credential, options)
 172        {
 173            AssertNoClientSideEncryption(options);
 174        }
 175
 176        /// <summary>
 177        /// Initializes a new instance of the <see cref="AppendBlobClient"/>
 178        /// class.
 179        /// </summary>
 180        /// <param name="blobUri">
 181        /// A <see cref="Uri"/> referencing the append blob that includes the
 182        /// name of the account, the name of the container, and the name of
 183        /// the blob.
 184        /// This is likely to be similar to "https://{account_name}.blob.core.windows.net/{container_name}/{blob_name}".
 185        /// </param>
 186        /// <param name="pipeline">
 187        /// The transport pipeline used to send every request.
 188        /// </param>
 189        /// <param name="version">
 190        /// The version of the service to use when sending requests.
 191        /// </param>
 192        /// <param name="clientDiagnostics">Client diagnostics.</param>
 193        /// <param name="customerProvidedKey">Customer provided key.</param>
 194        /// <param name="encryptionScope">Encryption scope.</param>
 195        internal AppendBlobClient(
 196            Uri blobUri,
 197            HttpPipeline pipeline,
 198            BlobClientOptions.ServiceVersion version,
 199            ClientDiagnostics clientDiagnostics,
 200            CustomerProvidedKey? customerProvidedKey,
 201            string encryptionScope)
 202            : base(
 203                  blobUri,
 204                  pipeline,
 205                  version,
 206                  clientDiagnostics,
 207                  customerProvidedKey,
 208                  clientSideEncryption: default,
 209                  encryptionScope)
 210        {
 211        }
 212
 213        private static void AssertNoClientSideEncryption(BlobClientOptions options)
 214        {
 215            if (options?._clientSideEncryptionOptions != default)
 216            {
 217                throw Errors.ClientSideEncryption.TypeNotSupported(typeof(AppendBlobClient));
 218            }
 219        }
 220        #endregion ctors
 221
 222        /// <summary>
 223        /// Initializes a new instance of the <see cref="AppendBlobClient"/>
 224        /// class with an identical <see cref="Uri"/> source but the specified
 225        /// <paramref name="snapshot"/> timestamp.
 226        ///
 227        /// For more information, see
 228        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/creating-a-snapshot-of-a-blob">
 229        /// Create a snapshot of a blob</see>.
 230        /// </summary>
 231        /// <param name="snapshot">The snapshot identifier.</param>
 232        /// <returns>A new <see cref="AppendBlobClient"/> instance.</returns>
 233        /// <remarks>
 234        /// Pass null or empty string to remove the snapshot returning a URL
 235        /// to the base blob.
 236        /// </remarks>
 237        public new AppendBlobClient WithSnapshot(string snapshot)
 238        {
 239            BlobUriBuilder blobUriBuilder = new BlobUriBuilder(Uri)
 240            {
 241                Snapshot = snapshot
 242            };
 243
 244            return new AppendBlobClient(
 245                blobUriBuilder.ToUri(),
 246                Pipeline,
 247                Version,
 248                ClientDiagnostics,
 249                CustomerProvidedKey,
 250                EncryptionScope);
 251        }
 252
 253        /// <summary>
 254        /// Initializes a new instance of the <see cref="AppendBlobClient"/>
 255        /// class with an identical <see cref="Uri"/> source but the specified
 256        /// <paramref name="versionId"/> timestamp.
 257        ///
 258        /// </summary>
 259        /// <param name="versionId">The version identifier.</param>
 260        /// <returns>A new <see cref="AppendBlobClient"/> instance.</returns>
 261        /// <remarks>
 262        /// Pass null or empty string to remove the version returning a URL
 263        /// to the base blob.
 264        /// </remarks>
 265        public new AppendBlobClient WithVersion(string versionId)
 266        {
 267            BlobUriBuilder blobUriBuilder = new BlobUriBuilder(Uri)
 268            {
 269                VersionId = versionId
 270            };
 271
 272            return new AppendBlobClient(
 273                blobUriBuilder.ToUri(),
 274                Pipeline,
 275                Version,
 276                ClientDiagnostics,
 277                CustomerProvidedKey,
 278                EncryptionScope);
 279        }
 280
 281        #region Create
 282        /// <summary>
 283        /// The <see cref="Create(AppendBlobCreateOptions, CancellationToken)"/>
 284        /// operation creates a new 0-length append blob.  The content of any existing
 285        /// blob is overwritten with the newly initialized append blob.  To add content
 286        /// to the append blob, call the <see cref="AppendBlock"/> operation.
 287        /// </summary>
 288        /// <param name="options">
 289        /// Optional parameters.
 290        /// </param>
 291        /// <param name="cancellationToken">
 292        /// Optional <see cref="CancellationToken"/> to propagate
 293        /// notifications that the operation should be cancelled.
 294        /// </param>
 295        /// <returns>
 296        /// A <see cref="Response{BlobContentInfo}"/> describing the
 297        /// newly created append blob.
 298        /// </returns>
 299        /// <remarks>
 300        /// A <see cref="RequestFailedException"/> will be thrown if
 301        /// a failure occurs.
 302        /// </remarks>
 303        public virtual Response<BlobContentInfo> Create(
 304            AppendBlobCreateOptions options,
 305            CancellationToken cancellationToken = default) =>
 306            CreateInternal(
 307                httpHeaders: options?.HttpHeaders,
 308                metadata: options?.Metadata,
 309                tags: options?.Tags,
 310                conditions: options?.Conditions,
 311                async: false,
 312                cancellationToken: cancellationToken)
 313            .EnsureCompleted();
 314
 315        /// <summary>
 316        /// The <see cref="CreateAsync(AppendBlobCreateOptions, CancellationToken)"/>
 317        /// operation creates a new 0-length append blob.  The content of any existing
 318        /// blob is overwritten with the newly initialized append blob.  To add content
 319        /// to the append blob, call the <see cref="AppendBlock"/> operation.
 320        /// </summary>
 321        /// <param name="options">
 322        /// Optional parameters.
 323        /// </param>
 324        /// <param name="cancellationToken">
 325        /// Optional <see cref="CancellationToken"/> to propagate
 326        /// notifications that the operation should be cancelled.
 327        /// </param>
 328        /// <returns>
 329        /// A <see cref="Response{BlobContentInfo}"/> describing the
 330        /// newly created append blob.
 331        /// </returns>
 332        /// <remarks>
 333        /// A <see cref="RequestFailedException"/> will be thrown if
 334        /// a failure occurs.
 335        /// </remarks>
 336        public virtual async Task<Response<BlobContentInfo>> CreateAsync(
 337            AppendBlobCreateOptions options,
 338            CancellationToken cancellationToken = default) =>
 339            await CreateInternal(
 340                httpHeaders: options?.HttpHeaders,
 341                metadata: options?.Metadata,
 342                tags: options?.Tags,
 343                conditions: options?.Conditions,
 344                async: true,
 345                cancellationToken: cancellationToken)
 346            .ConfigureAwait(false);
 347
 348        /// <summary>
 349        /// The <see cref="Create(BlobHttpHeaders, Metadata, AppendBlobRequestConditions, CancellationToken)"/>
 350        /// operation creates a new 0-length append blob.  The content of any existing blob is overwritten with
 351        /// the newly initialized append blob.  To add content to the append
 352        /// blob, call the <see cref="AppendBlock"/> operation.
 353        ///
 354        /// For more information, see
 355        /// <see href="https://docs.microsoft.com/rest/api/storageservices/put-blob">
 356        /// Put Blob</see>.
 357        /// </summary>
 358        /// <param name="httpHeaders">
 359        /// Optional standard HTTP header properties that can be set for the
 360        /// new append blob.
 361        /// </param>
 362        /// <param name="metadata">
 363        /// Optional custom metadata to set for this append blob.
 364        /// </param>
 365        /// <param name="conditions">
 366        /// Optional <see cref="AppendBlobRequestConditions"/> to add
 367        /// conditions on the creation of this new append blob.
 368        /// </param>
 369        /// <param name="cancellationToken">
 370        /// Optional <see cref="CancellationToken"/> to propagate
 371        /// notifications that the operation should be cancelled.
 372        /// </param>
 373        /// <returns>
 374        /// A <see cref="Response{BlobContentInfo}"/> describing the
 375        /// newly created append blob.
 376        /// </returns>
 377        /// <remarks>
 378        /// A <see cref="RequestFailedException"/> will be thrown if
 379        /// a failure occurs.
 380        /// </remarks>
 381        [EditorBrowsable(EditorBrowsableState.Never)]
 382        public virtual Response<BlobContentInfo> Create(
 383            BlobHttpHeaders httpHeaders = default,
 384            Metadata metadata = default,
 385            AppendBlobRequestConditions conditions = default,
 386            CancellationToken cancellationToken = default) =>
 387            CreateInternal(
 388                httpHeaders,
 389                metadata,
 390                default,
 391                conditions,
 392                false, // async
 393                cancellationToken)
 394                .EnsureCompleted();
 395
 396        /// <summary>
 397        /// The <see cref="CreateAsync(BlobHttpHeaders, Metadata, AppendBlobRequestConditions, CancellationToken)"/>
 398        /// operation creates a new 0-length append blob.  The content of any existing blob is overwritten with
 399        /// the newly initialized append blob.  To add content to the append
 400        /// blob, call the <see cref="AppendBlockAsync"/> operation.
 401        ///
 402        /// For more information, see
 403        /// <see href="https://docs.microsoft.com/rest/api/storageservices/put-blob">
 404        /// Put Blob</see>.
 405        /// </summary>
 406        /// <param name="httpHeaders">
 407        /// Optional standard HTTP header properties that can be set for the
 408        /// new append blob.
 409        /// </param>
 410        /// <param name="metadata">
 411        /// Optional custom metadata to set for this append blob.
 412        /// </param>
 413        /// <param name="conditions">
 414        /// Optional <see cref="AppendBlobRequestConditions"/> to add
 415        /// conditions on the creation of this new append blob.
 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        /// newly created append blob.
 424        /// </returns>
 425        /// <remarks>
 426        /// A <see cref="RequestFailedException"/> will be thrown if
 427        /// a failure occurs.
 428        /// </remarks>
 429        [EditorBrowsable(EditorBrowsableState.Never)]
 430        public virtual async Task<Response<BlobContentInfo>> CreateAsync(
 431            BlobHttpHeaders httpHeaders = default,
 432            Metadata metadata = default,
 433            AppendBlobRequestConditions conditions = default,
 434            CancellationToken cancellationToken = default) =>
 435            await CreateInternal(
 436                httpHeaders,
 437                metadata,
 438                default,
 439                conditions,
 440                true, // async
 441                cancellationToken)
 442                .ConfigureAwait(false);
 443
 444        /// <summary>
 445        /// The <see cref="CreateIfNotExists(AppendBlobCreateOptions, CancellationToken)"/>
 446        /// operation creates a new 0-length append blob.  If the append blob already exists,
 447        /// the content of the existing append blob will remain unchanged.  To add content to
 448        /// the append blob, call the <see cref="AppendBlockAsync"/> operation.
 449        ///
 450        /// For more information, see
 451        /// <see href="https://docs.microsoft.com/rest/api/storageservices/put-blob">
 452        /// Put Blob</see>.
 453        /// </summary>
 454        /// <param name="options">
 455        /// Optional parameters.
 456        /// </param>
 457        /// <param name="cancellationToken">
 458        /// Optional <see cref="CancellationToken"/> to propagate
 459        /// notifications that the operation should be cancelled.
 460        /// </param>
 461        /// <returns>
 462        /// If the append blob does not already exist, a <see cref="Response{BlobContentInfo}"/>
 463        /// describing the newly created append blob. Otherwise, <c>null</c>.
 464        /// </returns>
 465        /// <remarks>
 466        /// A <see cref="RequestFailedException"/> will be thrown if
 467        /// a failure occurs.
 468        /// </remarks>
 469        public virtual Response<BlobContentInfo> CreateIfNotExists(
 470            AppendBlobCreateOptions options,
 471            CancellationToken cancellationToken = default) =>
 472            CreateIfNotExistsInternal(
 473                options?.HttpHeaders,
 474                options?.Metadata,
 475                options?.Tags,
 476                async: false,
 477                cancellationToken: cancellationToken)
 478            .EnsureCompleted();
 479
 480        /// <summary>
 481        /// The <see cref="CreateIfNotExistsAsync(AppendBlobCreateOptions, CancellationToken)"/>
 482        /// operation creates a new 0-length append blob.  If the append blob already exists,
 483        /// the content of the existing append blob will remain unchanged.  To add content to
 484        /// the append blob, call the <see cref="AppendBlockAsync"/> operation.
 485        ///
 486        /// For more information, see
 487        /// <see href="https://docs.microsoft.com/rest/api/storageservices/put-blob">
 488        /// Put Blob</see>.
 489        /// </summary>
 490        /// <param name="options">
 491        /// Optional parameters.
 492        /// </param>
 493        /// <param name="cancellationToken">
 494        /// Optional <see cref="CancellationToken"/> to propagate
 495        /// notifications that the operation should be cancelled.
 496        /// </param>
 497        /// <returns>
 498        /// If the append blob does not already exist, a <see cref="Response{BlobContentInfo}"/>
 499        /// describing the newly created append blob. Otherwise, <c>null</c>.
 500        /// </returns>
 501        /// <remarks>
 502        /// A <see cref="RequestFailedException"/> will be thrown if
 503        /// a failure occurs.
 504        /// </remarks>
 505        public virtual async Task<Response<BlobContentInfo>> CreateIfNotExistsAsync(
 506            AppendBlobCreateOptions options,
 507            CancellationToken cancellationToken = default) =>
 508            await CreateIfNotExistsInternal(
 509                options?.HttpHeaders,
 510                options?.Metadata,
 511                options?.Tags,
 512                async: true,
 513                cancellationToken: cancellationToken)
 514            .ConfigureAwait(false);
 515
 516        /// <summary>
 517        /// The <see cref="CreateIfNotExists(BlobHttpHeaders, Metadata, CancellationToken)"/>
 518        /// operation creates a new 0-length append blob.  If the append blob already exists,
 519        /// the content of the existing append blob will remain unchanged.  To add content to
 520        /// the append blob, call the <see cref="AppendBlockAsync"/> operation.
 521        ///
 522        /// For more information, see
 523        /// <see href="https://docs.microsoft.com/rest/api/storageservices/put-blob">
 524        /// Put Blob</see>.
 525        /// </summary>
 526        /// <param name="httpHeaders">
 527        /// Optional standard HTTP header properties that can be set for the
 528        /// new append blob.
 529        /// </param>
 530        /// <param name="metadata">
 531        /// Optional custom metadata to set for this append blob.
 532        /// </param>
 533        /// <param name="cancellationToken">
 534        /// Optional <see cref="CancellationToken"/> to propagate
 535        /// notifications that the operation should be cancelled.
 536        /// </param>
 537        /// <returns>
 538        /// If the append blob does not already exist, a <see cref="Response{BlobContentInfo}"/>
 539        /// describing the newly created append blob. Otherwise, <c>null</c>.
 540        /// </returns>
 541        /// <remarks>
 542        /// A <see cref="RequestFailedException"/> will be thrown if
 543        /// a failure occurs.
 544        /// </remarks>
 545        [EditorBrowsable(EditorBrowsableState.Never)]
 546        public virtual Response<BlobContentInfo> CreateIfNotExists(
 547            BlobHttpHeaders httpHeaders = default,
 548            Metadata metadata = default,
 549            CancellationToken cancellationToken = default) =>
 550            CreateIfNotExistsInternal(
 551                httpHeaders,
 552                metadata,
 553                default,
 554                false, // async
 555                cancellationToken)
 556                .EnsureCompleted();
 557
 558        /// <summary>
 559        /// The <see cref="CreateIfNotExistsAsync(BlobHttpHeaders, Metadata, CancellationToken)"/>
 560        /// operation creates a new 0-length append blob.  If the append blob already exists,
 561        /// the content of the existing append blob will remain unchanged.  To add content to the append
 562        /// blob, call the <see cref="AppendBlockAsync"/> operation.
 563        ///
 564        /// For more information, see
 565        /// <see href="https://docs.microsoft.com/rest/api/storageservices/put-blob">
 566        /// Put Blob</see>.
 567        /// </summary>
 568        /// <param name="httpHeaders">
 569        /// Optional standard HTTP header properties that can be set for the
 570        /// new append blob.
 571        /// </param>
 572        /// <param name="metadata">
 573        /// Optional custom metadata to set for this append blob.
 574        /// </param>
 575        /// <param name="cancellationToken">
 576        /// Optional <see cref="CancellationToken"/> to propagate
 577        /// notifications that the operation should be cancelled.
 578        /// </param>
 579        /// <returns>
 580        /// If the append blob does not already exist, a <see cref="Response{BlobContentInfo}"/>
 581        /// describing the newly created append blob. Otherwise, <c>null</c>.
 582        /// </returns>
 583        /// <remarks>
 584        /// A <see cref="RequestFailedException"/> will be thrown if
 585        /// a failure occurs.
 586        /// </remarks>
 587        [EditorBrowsable(EditorBrowsableState.Never)]
 588        public virtual async Task<Response<BlobContentInfo>> CreateIfNotExistsAsync(
 589            BlobHttpHeaders httpHeaders = default,
 590            Metadata metadata = default,
 591            CancellationToken cancellationToken = default) =>
 592            await CreateIfNotExistsInternal(
 593                httpHeaders,
 594                metadata,
 595                default,
 596                true, // async
 597                cancellationToken)
 598                .ConfigureAwait(false);
 599
 600        /// <summary>
 601        /// The <see cref="CreateIfNotExistsInternal"/> operation creates a new 0-length
 602        /// append blob.  If the append blob already exists, the content of
 603        /// the existing append blob will remain unchanged.  To add content to the append
 604        /// blob, call the <see cref="AppendBlockAsync"/> operation.
 605        ///
 606        /// For more information, see
 607        /// <see href="https://docs.microsoft.com/rest/api/storageservices/put-blob">
 608        /// Put Blob</see>.
 609        /// </summary>
 610        /// <param name="httpHeaders">
 611        /// Optional standard HTTP header properties that can be set for the
 612        /// new append blob.
 613        /// </param>
 614        /// <param name="metadata">
 615        /// Optional custom metadata to set for this append blob.
 616        /// </param>
 617        /// <param name="tags">
 618        /// The tags to set on this append blob.
 619        /// </param>
 620        /// <param name="async">
 621        /// Whether to invoke the operation asynchronously.
 622        /// </param>
 623        /// <param name="cancellationToken">
 624        /// Optional <see cref="CancellationToken"/> to propagate
 625        /// notifications that the operation should be cancelled.
 626        /// </param>
 627        /// <returns>
 628        /// If the append blob does not already exist, a <see cref="Response{BlobContentInfo}"/>
 629        /// describing the newly created append blob. Otherwise, <c>null</c>.
 630        /// </returns>
 631        /// <remarks>
 632        /// A <see cref="RequestFailedException"/> will be thrown if
 633        /// a failure occurs.
 634        /// </remarks>
 635        private async Task<Response<BlobContentInfo>> CreateIfNotExistsInternal(
 636            BlobHttpHeaders httpHeaders,
 637            Metadata metadata,
 638            Tags tags,
 639            bool async,
 640            CancellationToken cancellationToken)
 641        {
 642            using (Pipeline.BeginLoggingScope(nameof(AppendBlobClient)))
 643            {
 644                Pipeline.LogMethodEnter(
 645                    nameof(AppendBlobClient),
 646                    message:
 647                    $"{nameof(Uri)}: {Uri}\n" +
 648                    $"{nameof(httpHeaders)}: {httpHeaders}");
 649                var conditions = new AppendBlobRequestConditions { IfNoneMatch = new ETag(Constants.Wildcard) };
 650                try
 651                {
 652                    Response<BlobContentInfo> response = await CreateInternal(
 653                        httpHeaders,
 654                        metadata,
 655                        tags,
 656                        conditions,
 657                        async,
 658                        cancellationToken,
 659                        $"{nameof(AppendBlobClient)}.{nameof(CreateIfNotExists)}")
 660                        .ConfigureAwait(false);
 661
 662                    return response;
 663                }
 664                catch (RequestFailedException storageRequestFailedException)
 665                when (storageRequestFailedException.ErrorCode == BlobErrorCode.BlobAlreadyExists)
 666                {
 667                    return default;
 668                }
 669                catch (Exception ex)
 670                {
 671                    Pipeline.LogException(ex);
 672                    throw;
 673                }
 674                finally
 675                {
 676                    Pipeline.LogMethodExit(nameof(AppendBlobClient));
 677                }
 678            }
 679        }
 680
 681        /// <summary>
 682        /// The <see cref="CreateInternal"/> operation creates a new 0-length
 683        /// append blob.  The content of any existing blob is overwritten with
 684        /// the newly initialized append blob.  To add content to the append
 685        /// blob, call the <see cref="AppendBlockAsync"/> operation.
 686        ///
 687        /// For more information, see
 688        /// <see href="https://docs.microsoft.com/rest/api/storageservices/put-blob">
 689        /// Put Blob</see>.
 690        /// </summary>
 691        /// <param name="httpHeaders">
 692        /// Optional standard HTTP header properties that can be set for the
 693        /// new append blob.
 694        /// </param>
 695        /// <param name="metadata">
 696        /// Optional custom metadata to set for this append blob.
 697        /// </param>
 698        /// <param name="tags">
 699        /// The tags to set on this append blob.
 700        /// </param>
 701        /// <param name="conditions">
 702        /// Optional <see cref="AppendBlobRequestConditions"/> to add
 703        /// conditions on the creation of this new append blob.
 704        /// </param>
 705        /// <param name="async">
 706        /// Whether to invoke the operation asynchronously.
 707        /// </param>
 708        /// <param name="cancellationToken">
 709        /// Optional <see cref="CancellationToken"/> to propagate
 710        /// notifications that the operation should be cancelled.
 711        /// </param>
 712        /// <param name="operationName">
 713        /// Optional. To indicate if the name of the operation.
 714        /// </param>
 715        /// <returns>
 716        /// A <see cref="Response{BlobContentInfo}"/> describing the
 717        /// newly created append blob.
 718        /// </returns>
 719        /// <remarks>
 720        /// A <see cref="RequestFailedException"/> will be thrown if
 721        /// a failure occurs.
 722        /// </remarks>
 723        private async Task<Response<BlobContentInfo>> CreateInternal(
 724            BlobHttpHeaders httpHeaders,
 725            Metadata metadata,
 726            Tags tags,
 727            AppendBlobRequestConditions conditions,
 728            bool async,
 729            CancellationToken cancellationToken,
 730            string operationName = null)
 731        {
 732            using (Pipeline.BeginLoggingScope(nameof(AppendBlobClient)))
 733            {
 734                Pipeline.LogMethodEnter(
 735                    nameof(AppendBlobClient),
 736                    message:
 737                    $"{nameof(Uri)}: {Uri}\n" +
 738                    $"{nameof(httpHeaders)}: {httpHeaders}\n" +
 739                    $"{nameof(conditions)}: {conditions}");
 740                try
 741                {
 742                    return await BlobRestClient.AppendBlob.CreateAsync(
 743                        ClientDiagnostics,
 744                        Pipeline,
 745                        Uri,
 746                        contentLength: default,
 747                        version: Version.ToVersionString(),
 748                        blobContentType: httpHeaders?.ContentType,
 749                        blobContentEncoding: httpHeaders?.ContentEncoding,
 750                        blobContentLanguage: httpHeaders?.ContentLanguage,
 751                        blobContentHash: httpHeaders?.ContentHash,
 752                        blobCacheControl: httpHeaders?.CacheControl,
 753                        metadata: metadata,
 754                        leaseId: conditions?.LeaseId,
 755                        blobContentDisposition: httpHeaders?.ContentDisposition,
 756                        encryptionKey: CustomerProvidedKey?.EncryptionKey,
 757                        encryptionKeySha256: CustomerProvidedKey?.EncryptionKeyHash,
 758                        encryptionAlgorithm: CustomerProvidedKey?.EncryptionAlgorithm,
 759                        encryptionScope: EncryptionScope,
 760                        ifModifiedSince: conditions?.IfModifiedSince,
 761                        ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
 762                        ifMatch: conditions?.IfMatch,
 763                        ifNoneMatch: conditions?.IfNoneMatch,
 764                        ifTags: conditions?.TagConditions,
 765                        blobTagsString: tags?.ToTagsString(),
 766                        async: async,
 767                        operationName: operationName ?? $"{nameof(AppendBlobClient)}.{nameof(Create)}",
 768                        cancellationToken: cancellationToken)
 769                        .ConfigureAwait(false);
 770                }
 771                catch (Exception ex)
 772                {
 773                    Pipeline.LogException(ex);
 774                    throw;
 775                }
 776                finally
 777                {
 778                    Pipeline.LogMethodExit(nameof(AppendBlobClient));
 779                }
 780            }
 781        }
 782        #endregion Create
 783
 784        #region AppendBlock
 785        /// <summary>
 786        /// The <see cref="AppendBlock"/> operation commits a new block
 787        /// of data, represented by the <paramref name="content"/> <see cref="Stream"/>,
 788        /// to the end of the existing append blob.  The <see cref="AppendBlock"/>
 789        /// operation is only permitted if the blob was created as an append
 790        /// blob.
 791        ///
 792        /// For more information, see
 793        /// <see href="https://docs.microsoft.com/rest/api/storageservices/append-block">
 794        /// Append Block</see>.
 795        /// </summary>
 796        /// <param name="content">
 797        /// A <see cref="Stream"/> containing the content of the block to
 798        /// append.
 799        /// </param>
 800        /// <param name="transactionalContentHash">
 801        /// Optional MD5 hash of the block content.  This hash is used to
 802        /// verify the integrity of the block during transport. When this hash
 803        /// is specified, the storage service compares the hash of the content
 804        /// that has arrived with this value.  Note that this MD5 hash is not
 805        /// stored with the blob.  If the two hashes do not match, the
 806        /// operation will fail with a <see cref="RequestFailedException"/>.
 807        /// </param>
 808        /// <param name="conditions">
 809        /// Optional <see cref="AppendBlobRequestConditions"/> to add
 810        /// conditions on appending content to this append blob.
 811        /// </param>
 812        /// <param name="progressHandler">
 813        /// Optional <see cref="IProgress{Long}"/> to provide
 814        /// progress updates about data transfers.
 815        /// </param>
 816        /// <param name="cancellationToken">
 817        /// Optional <see cref="CancellationToken"/> to propagate
 818        /// notifications that the operation should be cancelled.
 819        /// </param>
 820        /// <returns>
 821        /// A <see cref="Response{BlobAppendInfo}"/> describing the
 822        /// state of the updated append blob.
 823        /// </returns>
 824        /// <remarks>
 825        /// A <see cref="RequestFailedException"/> will be thrown if
 826        /// a failure occurs.
 827        /// </remarks>
 828        public virtual Response<BlobAppendInfo> AppendBlock(
 829            Stream content,
 830            byte[] transactionalContentHash = default,
 831            AppendBlobRequestConditions conditions = default,
 832            IProgress<long> progressHandler = default,
 833            CancellationToken cancellationToken = default) =>
 834            AppendBlockInternal(
 835                content,
 836                transactionalContentHash,
 837                conditions,
 838                progressHandler,
 839                false, // async
 840                cancellationToken)
 841                .EnsureCompleted();
 842
 843        /// <summary>
 844        /// The <see cref="AppendBlockAsync"/> operation commits a new block
 845        /// of data, represented by the <paramref name="content"/> <see cref="Stream"/>,
 846        /// to the end of the existing append blob.  The <see cref="AppendBlockAsync"/>
 847        /// operation is only permitted if the blob was created as an append
 848        /// blob.
 849        ///
 850        /// For more information, see
 851        /// <see href="https://docs.microsoft.com/rest/api/storageservices/append-block">
 852        /// Append Block</see>.
 853        /// </summary>
 854        /// <param name="content">
 855        /// A <see cref="Stream"/> containing the content of the block to
 856        /// append.
 857        /// </param>
 858        /// <param name="transactionalContentHash">
 859        /// Optional MD5 hash of the block content.  This hash is used to
 860        /// verify the integrity of the block during transport. When this hash
 861        /// is specified, the storage service compares the hash of the content
 862        /// that has arrived with this value.  Note that this MD5 hash is not
 863        /// stored with the blob.  If the two hashes do not match, the
 864        /// operation will fail with a <see cref="RequestFailedException"/>.
 865        /// </param>
 866        /// <param name="conditions">
 867        /// Optional <see cref="AppendBlobRequestConditions"/> to add
 868        /// conditions on appending content to this append blob.
 869        /// </param>
 870        /// <param name="progressHandler">
 871        /// Optional <see cref="IProgress{Long}"/> to provide
 872        /// progress updates about data transfers.
 873        /// </param>
 874        /// <param name="cancellationToken">
 875        /// Optional <see cref="CancellationToken"/> to propagate
 876        /// notifications that the operation should be cancelled.
 877        /// </param>
 878        /// <returns>
 879        /// A <see cref="Response{BlobAppendInfo}"/> describing the
 880        /// state of the updated append blob.
 881        /// </returns>
 882        /// <remarks>
 883        /// A <see cref="RequestFailedException"/> will be thrown if
 884        /// a failure occurs.
 885        /// </remarks>
 886        public virtual async Task<Response<BlobAppendInfo>> AppendBlockAsync(
 887            Stream content,
 888            byte[] transactionalContentHash = default,
 889            AppendBlobRequestConditions conditions = default,
 890            IProgress<long> progressHandler = default,
 891            CancellationToken cancellationToken = default) =>
 892            await AppendBlockInternal(
 893                content,
 894                transactionalContentHash,
 895                conditions,
 896                progressHandler,
 897                true, // async
 898                cancellationToken)
 899                .ConfigureAwait(false);
 900
 901        /// <summary>
 902        /// The <see cref="AppendBlockInternal"/> operation commits a new block
 903        /// of data, represented by the <paramref name="content"/> <see cref="Stream"/>,
 904        /// to the end of the existing append blob.  The <see cref="AppendBlockInternal"/>
 905        /// operation is only permitted if the blob was created as an append
 906        /// blob.
 907        ///
 908        /// For more information, see
 909        /// <see href="https://docs.microsoft.com/rest/api/storageservices/append-block">
 910        /// Append Block</see>.
 911        /// </summary>
 912        /// <param name="content">
 913        /// A <see cref="Stream"/> containing the content of the block to
 914        /// append.
 915        /// </param>
 916        /// <param name="transactionalContentHash">
 917        /// Optional MD5 hash of the block content.  This hash is used to
 918        /// verify the integrity of the block during transport. When this hash
 919        /// is specified, the storage service compares the hash of the content
 920        /// that has arrived with this value.  Note that this MD5 hash is not
 921        /// stored with the blob.  If the two hashes do not match, the
 922        /// operation will fail with a <see cref="RequestFailedException"/>.
 923        /// </param>
 924        /// <param name="conditions">
 925        /// Optional <see cref="AppendBlobRequestConditions"/> to add
 926        /// conditions on appending content to this append blob.
 927        /// </param>
 928        /// <param name="progressHandler">
 929        /// Optional <see cref="IProgress{Long}"/> to provide
 930        /// progress updates about data transfers.
 931        /// </param>
 932        /// <param name="async">
 933        /// Whether to invoke the operation asynchronously.
 934        /// </param>
 935        /// <param name="cancellationToken">
 936        /// Optional <see cref="CancellationToken"/> to propagate
 937        /// notifications that the operation should be cancelled.
 938        /// </param>
 939        /// <returns>
 940        /// A <see cref="Response{BlobAppendInfo}"/> describing the
 941        /// state of the updated append blob.
 942        /// </returns>
 943        /// <remarks>
 944        /// A <see cref="RequestFailedException"/> will be thrown if
 945        /// a failure occurs.
 946        /// </remarks>
 947        private async Task<Response<BlobAppendInfo>> AppendBlockInternal(
 948            Stream content,
 949            byte[] transactionalContentHash,
 950            AppendBlobRequestConditions conditions,
 951            IProgress<long> progressHandler,
 952            bool async,
 953            CancellationToken cancellationToken)
 954        {
 955            using (Pipeline.BeginLoggingScope(nameof(AppendBlobClient)))
 956            {
 957                Pipeline.LogMethodEnter(
 958                    nameof(AppendBlobClient),
 959                    message:
 960                    $"{nameof(Uri)}: {Uri}\n" +
 961                    $"{nameof(conditions)}: {conditions}");
 962                try
 963                {
 964                    BlobErrors.VerifyHttpsCustomerProvidedKey(Uri, CustomerProvidedKey);
 965
 966                    content = content?.WithNoDispose().WithProgress(progressHandler);
 967                    return await BlobRestClient.AppendBlob.AppendBlockAsync(
 968                        ClientDiagnostics,
 969                        Pipeline,
 970                        Uri,
 971                        body: content,
 972                        contentLength: content?.Length ?? 0,
 973                        version: Version.ToVersionString(),
 974                        transactionalContentHash: transactionalContentHash,
 975                        leaseId: conditions?.LeaseId,
 976                        maxSize: conditions?.IfMaxSizeLessThanOrEqual,
 977                        encryptionKey: CustomerProvidedKey?.EncryptionKey,
 978                        encryptionKeySha256: CustomerProvidedKey?.EncryptionKeyHash,
 979                        encryptionAlgorithm: CustomerProvidedKey?.EncryptionAlgorithm,
 980                        encryptionScope: EncryptionScope,
 981                        appendPosition: conditions?.IfAppendPositionEqual,
 982                        ifModifiedSince: conditions?.IfModifiedSince,
 983                        ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
 984                        ifMatch: conditions?.IfMatch,
 985                        ifNoneMatch: conditions?.IfNoneMatch,
 986                        ifTags: conditions?.TagConditions,
 987                        async: async,
 988                        operationName: "AppendBlobClient.AppendBlock",
 989                        cancellationToken: cancellationToken).ConfigureAwait(false);
 990                }
 991                catch (Exception ex)
 992                {
 993                    Pipeline.LogException(ex);
 994                    throw;
 995                }
 996                finally
 997                {
 998                    Pipeline.LogMethodExit(nameof(AppendBlobClient));
 999                }
 1000            }
 1001        }
 1002        #endregion AppendBlock
 1003
 1004        #region AppendBlockFromUri
 1005        /// <summary>
 1006        /// The <see cref="AppendBlockFromUri"/> operation commits a new
 1007        /// block of data, represented by the <paramref name="sourceUri"/>,
 1008        /// to the end of the existing append blob.  The
 1009        /// <see cref="AppendBlockFromUri"/> operation is only permitted
 1010        /// if the blob was created as an append blob.
 1011        ///
 1012        /// For more information, see
 1013        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/append-block-from-url">
 1014        /// Append Block From URL</see>.
 1015        /// </summary>
 1016        /// <param name="sourceUri">
 1017        /// Specifies the <see cref="Uri"/> of the source blob.  The value may
 1018        /// be a <see cref="Uri"/> of up to 2 KB in length that specifies a
 1019        /// blob.  The source blob must either be public or must be
 1020        /// authenticated via a shared access signature.  If the source blob
 1021        /// is public, no authentication is required to perform the operation.
 1022        /// </param>
 1023        /// <param name="sourceRange">
 1024        /// Optionally only upload the bytes of the blob in the
 1025        /// <paramref name="sourceUri"/> in the specified range.  If this is
 1026        /// not specified, the entire source blob contents are uploaded as a
 1027        /// single append block.
 1028        /// </param>
 1029        /// <param name="sourceContentHash">
 1030        /// Optional MD5 hash of the append block content from the
 1031        /// <paramref name="sourceUri"/>.  This hash is used to verify the
 1032        /// integrity of the block during transport of the data from the Uri.
 1033        /// When this hash is specified, the storage service compares the hash
 1034        /// of the content that has arrived from the <paramref name="sourceUri"/>
 1035        /// with this value.  Note that this md5 hash is not stored with the
 1036        /// blob.  If the two hashes do not match, the operation will fail
 1037        /// with a <see cref="RequestFailedException"/>.
 1038        /// </param>
 1039        /// <param name="conditions">
 1040        /// Optional <see cref="AppendBlobRequestConditions"/> to add
 1041        /// conditions on the copying of data to this append blob.
 1042        /// </param>
 1043        /// <param name="sourceConditions">
 1044        /// Optional <see cref="AppendBlobRequestConditions"/> to add
 1045        /// conditions on the copying of data from this source blob.
 1046        /// </param>
 1047        /// <param name="cancellationToken">
 1048        /// Optional <see cref="CancellationToken"/> to propagate
 1049        /// notifications that the operation should be cancelled.
 1050        /// </param>
 1051        /// <returns>
 1052        /// A <see cref="Response{BlobAppendInfo}"/> describing the
 1053        /// state of the updated append blob.
 1054        /// </returns>
 1055        /// <remarks>
 1056        /// A <see cref="RequestFailedException"/> will be thrown if
 1057        /// a failure occurs.
 1058        /// </remarks>
 1059        public virtual Response<BlobAppendInfo> AppendBlockFromUri(
 1060            Uri sourceUri,
 1061            HttpRange sourceRange = default,
 1062            byte[] sourceContentHash = default,
 1063            AppendBlobRequestConditions conditions = default,
 1064            AppendBlobRequestConditions sourceConditions = default,
 1065            CancellationToken cancellationToken = default) =>
 1066            AppendBlockFromUriInternal(
 1067                sourceUri,
 1068                sourceRange,
 1069                sourceContentHash,
 1070                conditions,
 1071                sourceConditions,
 1072                false, // async
 1073                cancellationToken)
 1074                .EnsureCompleted();
 1075
 1076        /// <summary>
 1077        /// The <see cref="AppendBlockFromUriAsync"/> operation commits a new
 1078        /// block of data, represented by the <paramref name="sourceUri"/>,
 1079        /// to the end of the existing append blob.  The
 1080        /// <see cref="AppendBlockFromUriAsync"/> operation is only permitted
 1081        /// if the blob was created as an append blob.
 1082        ///
 1083        /// For more information, see
 1084        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/append-block-from-url">
 1085        /// Append Block From URL</see>.
 1086        /// </summary>
 1087        /// <param name="sourceUri">
 1088        /// Specifies the <see cref="Uri"/> of the source blob.  The value may
 1089        /// be a <see cref="Uri"/> of up to 2 KB in length that specifies a
 1090        /// blob.  The source blob must either be public or must be
 1091        /// authenticated via a shared access signature.  If the source blob
 1092        /// is public, no authentication is required to perform the operation.
 1093        /// </param>
 1094        /// <param name="sourceRange">
 1095        /// Optionally only upload the bytes of the blob in the
 1096        /// <paramref name="sourceUri"/> in the specified range.  If this is
 1097        /// not specified, the entire source blob contents are uploaded as a
 1098        /// single append block.
 1099        /// </param>
 1100        /// <param name="sourceContentHash">
 1101        /// Optional MD5 hash of the append block content from the
 1102        /// <paramref name="sourceUri"/>.  This hash is used to verify the
 1103        /// integrity of the block during transport of the data from the Uri.
 1104        /// When this hash is specified, the storage service compares the hash
 1105        /// of the content that has arrived from the <paramref name="sourceUri"/>
 1106        /// with this value.  Note that this md5 hash is not stored with the
 1107        /// blob.  If the two hashes do not match, the operation will fail
 1108        /// with a <see cref="RequestFailedException"/>.
 1109        /// </param>
 1110        /// <param name="conditions">
 1111        /// Optional <see cref="AppendBlobRequestConditions"/> to add
 1112        /// conditions on the copying of data to this append blob.
 1113        /// </param>
 1114        /// <param name="sourceConditions">
 1115        /// Optional <see cref="AppendBlobRequestConditions"/> to add
 1116        /// conditions on the copying of data from this source blob.
 1117        /// </param>
 1118        /// <param name="cancellationToken">
 1119        /// Optional <see cref="CancellationToken"/> to propagate
 1120        /// notifications that the operation should be cancelled.
 1121        /// </param>
 1122        /// <returns>
 1123        /// A <see cref="Response{BlobAppendInfo}"/> describing the
 1124        /// state of the updated append blob.
 1125        /// </returns>
 1126        /// <remarks>
 1127        /// A <see cref="RequestFailedException"/> will be thrown if
 1128        /// a failure occurs.
 1129        /// </remarks>
 1130        public virtual async Task<Response<BlobAppendInfo>> AppendBlockFromUriAsync(
 1131            Uri sourceUri,
 1132            HttpRange sourceRange = default,
 1133            byte[] sourceContentHash = default,
 1134            AppendBlobRequestConditions conditions = default,
 1135            AppendBlobRequestConditions sourceConditions = default,
 1136            CancellationToken cancellationToken = default) =>
 1137            await AppendBlockFromUriInternal(
 1138                sourceUri,
 1139                sourceRange,
 1140                sourceContentHash,
 1141                conditions,
 1142                sourceConditions,
 1143                true,  // async
 1144                cancellationToken)
 1145                .ConfigureAwait(false);
 1146
 1147        /// <summary>
 1148        /// The <see cref="AppendBlockFromUriInternal"/> operation commits a new
 1149        /// block of data, represented by the <paramref name="sourceUri"/>,
 1150        /// to the end of the existing append blob.  The
 1151        /// <see cref="AppendBlockFromUriInternal"/> operation is only permitted
 1152        /// if the blob was created as an append blob.
 1153        ///
 1154        /// For more information, see
 1155        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/append-block-from-url">
 1156        /// Append Block From URL</see>.
 1157        /// </summary>
 1158        /// <param name="sourceUri">
 1159        /// Specifies the <see cref="Uri"/> of the source blob.  The value may
 1160        /// be a <see cref="Uri"/> of up to 2 KB in length that specifies a
 1161        /// blob.  The source blob must either be public or must be
 1162        /// authenticated via a shared access signature.  If the source blob
 1163        /// is public, no authentication is required to perform the operation.
 1164        /// </param>
 1165        /// <param name="sourceRange">
 1166        /// Optionally only upload the bytes of the blob in the
 1167        /// <paramref name="sourceUri"/> in the specified range.  If this is
 1168        /// not specified, the entire source blob contents are uploaded as a
 1169        /// single append block.
 1170        /// </param>
 1171        /// <param name="sourceContentHash">
 1172        /// Optional MD5 hash of the append block content from the
 1173        /// <paramref name="sourceUri"/>.  This hash is used to verify the
 1174        /// integrity of the block during transport of the data from the Uri.
 1175        /// When this hash is specified, the storage service compares the hash
 1176        /// of the content that has arrived from the <paramref name="sourceUri"/>
 1177        /// with this value.  Note that this md5 hash is not stored with the
 1178        /// blob.  If the two hashes do not match, the operation will fail
 1179        /// with a <see cref="RequestFailedException"/>.
 1180        /// </param>
 1181        /// <param name="conditions">
 1182        /// Optional <see cref="AppendBlobRequestConditions"/> to add
 1183        /// conditions on the copying of data to this append blob.
 1184        /// </param>
 1185        /// <param name="sourceConditions">
 1186        /// Optional <see cref="AppendBlobRequestConditions"/> to add
 1187        /// conditions on the copying of data from this source blob.
 1188        /// </param>
 1189        /// <param name="async">
 1190        /// Whether to invoke the operation asynchronously.
 1191        /// </param>
 1192        /// <param name="cancellationToken">
 1193        /// Optional <see cref="CancellationToken"/> to propagate
 1194        /// notifications that the operation should be cancelled.
 1195        /// </param>
 1196        /// <returns>
 1197        /// A <see cref="Response{BlobAppendInfo}"/> describing the
 1198        /// state of the updated append blob.
 1199        /// </returns>
 1200        /// <remarks>
 1201        /// A <see cref="RequestFailedException"/> will be thrown if
 1202        /// a failure occurs.
 1203        /// </remarks>
 1204        private async Task<Response<BlobAppendInfo>> AppendBlockFromUriInternal(
 1205            Uri sourceUri,
 1206            HttpRange sourceRange,
 1207            byte[] sourceContentHash,
 1208            AppendBlobRequestConditions conditions,
 1209            AppendBlobRequestConditions sourceConditions,
 1210            bool async,
 1211            CancellationToken cancellationToken = default)
 1212        {
 1213            using (Pipeline.BeginLoggingScope(nameof(AppendBlobClient)))
 1214            {
 1215                Pipeline.LogMethodEnter(
 1216                    nameof(AppendBlobClient),
 1217                    message:
 1218                    $"{nameof(Uri)}: {Uri}\n" +
 1219                    $"{nameof(sourceUri)}: {sourceUri}\n" +
 1220                    $"{nameof(conditions)}: {conditions}");
 1221                try
 1222                {
 1223                    return await BlobRestClient.AppendBlob.AppendBlockFromUriAsync(
 1224                        ClientDiagnostics,
 1225                        Pipeline,
 1226                        Uri,
 1227                        sourceUri: sourceUri,
 1228                        sourceRange: sourceRange.ToString(),
 1229                        sourceContentHash: sourceContentHash,
 1230                        contentLength: default,
 1231                        version: Version.ToVersionString(),
 1232                        encryptionKey: CustomerProvidedKey?.EncryptionKey,
 1233                        encryptionKeySha256: CustomerProvidedKey?.EncryptionKeyHash,
 1234                        encryptionAlgorithm: CustomerProvidedKey?.EncryptionAlgorithm,
 1235                        encryptionScope: EncryptionScope,
 1236                        leaseId: conditions?.LeaseId,
 1237                        maxSize: conditions?.IfMaxSizeLessThanOrEqual,
 1238                        appendPosition: conditions?.IfAppendPositionEqual,
 1239                        ifModifiedSince: conditions?.IfModifiedSince,
 1240                        ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
 1241                        ifMatch: conditions?.IfMatch,
 1242                        ifNoneMatch: conditions?.IfNoneMatch,
 1243                        ifTags: conditions?.TagConditions,
 1244                        sourceIfModifiedSince: sourceConditions?.IfModifiedSince,
 1245                        sourceIfUnmodifiedSince: sourceConditions?.IfUnmodifiedSince,
 1246                        sourceIfMatch: sourceConditions?.IfMatch,
 1247                        sourceIfNoneMatch: sourceConditions?.IfNoneMatch,
 1248                        async: async,
 1249                        operationName: "AppendBlobClient.AppendBlockFromUri",
 1250                        cancellationToken: cancellationToken)
 1251                        .ConfigureAwait(false);
 1252                }
 1253                catch (Exception ex)
 1254                {
 1255                    Pipeline.LogException(ex);
 1256                    throw;
 1257                }
 1258                finally
 1259                {
 1260                    Pipeline.LogMethodExit(nameof(AppendBlobClient));
 1261                }
 1262            }
 1263        }
 1264        #endregion AppendBlockFromUri
 1265
 1266        #region Seal
 1267        /// <summary>
 1268        /// Seals the append blob, making it read only.
 1269        /// Any subsequent appends will fail.
 1270        /// </summary>
 1271        /// <param name="conditions">
 1272        /// Optional <see cref="AppendBlobRequestConditions"/> to add
 1273        /// conditions on the sealing of this blob.
 1274        /// </param>
 1275        /// <param name="cancellationToken">
 1276        /// Optional <see cref="CancellationToken"/> to propagate
 1277        /// notifications that the operation should be cancelled.
 1278        /// </param>
 1279        /// <returns>
 1280        /// A <see cref="Response{BlobInfo}"/> describing the
 1281        /// state of the sealed append blob.
 1282        /// </returns>
 1283        /// <remarks>
 1284        /// A <see cref="RequestFailedException"/> will be thrown if
 1285        /// a failure occurs.
 1286        /// </remarks>
 1287        public virtual Response<BlobInfo> Seal(
 1288            AppendBlobRequestConditions conditions = default,
 1289            CancellationToken cancellationToken = default)
 1290            => SealInternal(
 1291                conditions,
 1292                async: false,
 1293                cancellationToken: cancellationToken)
 1294                .EnsureCompleted();
 1295
 1296        /// <summary>
 1297        /// Seals the append blob, making it read only.
 1298        /// Any subsequent appends will fail.
 1299        /// </summary>
 1300        /// <param name="conditions">
 1301        /// Optional <see cref="AppendBlobRequestConditions"/> to add
 1302        /// conditions on the sealing of this blob.
 1303        /// </param>
 1304        /// <param name="cancellationToken">
 1305        /// Optional <see cref="CancellationToken"/> to propagate
 1306        /// notifications that the operation should be cancelled.
 1307        /// </param>
 1308        /// <returns>
 1309        /// A <see cref="Response{BlobInfo}"/> describing the
 1310        /// state of the sealed append blob.
 1311        /// </returns>
 1312        /// <remarks>
 1313        /// A <see cref="RequestFailedException"/> will be thrown if
 1314        /// a failure occurs.
 1315        /// </remarks>
 1316        public virtual async Task<Response<BlobInfo>> SealAsync(
 1317            AppendBlobRequestConditions conditions = default,
 1318            CancellationToken cancellationToken = default)
 1319            => await SealInternal(
 1320                conditions,
 1321                async: true,
 1322                cancellationToken: cancellationToken)
 1323                .ConfigureAwait(false);
 1324
 1325        /// <summary>
 1326        /// Seals the append blob, making it read only.
 1327        /// Any subsequent appends will fail.
 1328        /// </summary>
 1329        /// <param name="conditions">
 1330        /// Optional <see cref="AppendBlobRequestConditions"/> to add
 1331        /// conditions on the sealing of this blob.
 1332        /// </param>
 1333        /// <param name="async">
 1334        /// Whether to invoke the operation asynchronously.
 1335        /// </param>
 1336        /// <param name="cancellationToken">
 1337        /// Optional <see cref="CancellationToken"/> to propagate
 1338        /// notifications that the operation should be cancelled.
 1339        /// </param>
 1340        /// <returns>
 1341        /// A <see cref="Response{BlobInfo}"/> describing the
 1342        /// state of the sealed append blob.
 1343        /// </returns>
 1344        /// <remarks>
 1345        /// A <see cref="RequestFailedException"/> will be thrown if
 1346        /// a failure occurs.
 1347        /// </remarks>
 1348        private async Task<Response<BlobInfo>> SealInternal(
 1349            AppendBlobRequestConditions conditions,
 1350            bool async,
 1351            CancellationToken cancellationToken)
 1352        {
 1353            using (Pipeline.BeginLoggingScope(nameof(AppendBlobClient)))
 1354            {
 1355                try
 1356                {
 1357                    Response<AppendBlobSealInternal> response = await BlobRestClient.AppendBlob.SealAsync(
 1358                        ClientDiagnostics,
 1359                        Pipeline,
 1360                        Uri,
 1361                        Version.ToVersionString(),
 1362                        leaseId: conditions?.LeaseId,
 1363                        ifModifiedSince: conditions?.IfModifiedSince,
 1364                        ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
 1365                        ifMatch: conditions?.IfMatch,
 1366                        ifNoneMatch: conditions?.IfNoneMatch,
 1367                        appendPosition: conditions?.IfAppendPositionEqual,
 1368                        async: async,
 1369                        operationName: $"{nameof(AppendBlobClient)}.{nameof(Seal)}",
 1370                        cancellationToken: cancellationToken)
 1371                        .ConfigureAwait(false);
 1372
 1373                    return Response.FromValue(
 1374                        new BlobInfo
 1375                        {
 1376                            ETag = response.Value.ETag,
 1377                            LastModified = response.Value.LastModified
 1378                        },
 1379                        response.GetRawResponse());
 1380                }
 1381                catch (Exception ex)
 1382                {
 1383                    Pipeline.LogException(ex);
 1384                    throw;
 1385                }
 1386                finally
 1387                {
 1388                    Pipeline.LogMethodExit(nameof(AppendBlobClient));
 1389                }
 1390            }
 1391        }
 1392        #endregion Seal
 1393    }
 1394
 1395    /// <summary>
 1396    /// Add easy to discover methods to <see cref="BlobContainerClient"/> for
 1397    /// creating <see cref="AppendBlobClient"/> instances.
 1398    /// </summary>
 1399    public static partial class SpecializedBlobExtensions
 1400    {
 1401        /// <summary>
 1402        /// Create a new <see cref="AppendBlobClient"/> object by
 1403        /// concatenating <paramref name="blobName"/> to
 1404        /// the end of the <paramref name="client"/>'s
 1405        /// <see cref="BlobContainerClient.Uri"/>. The new
 1406        /// <see cref="AppendBlobClient"/>
 1407        /// uses the same request policy pipeline as the
 1408        /// <see cref="BlobContainerClient"/>.
 1409        /// </summary>
 1410        /// <param name="client">The <see cref="BlobContainerClient"/>.</param>
 1411        /// <param name="blobName">The name of the append blob.</param>
 1412        /// <returns>A new <see cref="AppendBlobClient"/> instance.</returns>
 1413        public static AppendBlobClient GetAppendBlobClient(
 1414            this BlobContainerClient client,
 1415            string blobName)
 1416        {
 6961417            if (client.ClientSideEncryption != default)
 1418            {
 01419                throw Errors.ClientSideEncryption.TypeNotSupported(typeof(AppendBlobClient));
 1420            }
 1421
 6961422            BlobUriBuilder blobUriBuilder = new BlobUriBuilder(client.Uri)
 6961423            {
 6961424                BlobName = blobName
 6961425            };
 1426
 6961427            return new AppendBlobClient(
 6961428                blobUriBuilder.ToUri(),
 6961429                client.Pipeline,
 6961430                client.Version,
 6961431                client.ClientDiagnostics,
 6961432                client.CustomerProvidedKey,
 6961433                client.EncryptionScope);
 1434        }
 1435    }
 1436}

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

#LineLine coverage
 1// Copyright (c) Microsoft Corporation. All rights reserved.
 2// Licensed under the MIT License.
 3
 4using System;
 5using System.ComponentModel;
 6using System.Diagnostics;
 7using System.IO;
 8using System.Threading;
 9using System.Threading.Tasks;
 10using Azure.Core;
 11using Azure.Core.Pipeline;
 12using Azure.Storage.Blobs.Models;
 13using Azure.Storage.Cryptography;
 14using Azure.Storage.Shared;
 15using Metadata = System.Collections.Generic.IDictionary<string, string>;
 16using Tags = System.Collections.Generic.IDictionary<string, string>;
 17
 18#pragma warning disable SA1402  // File may only contain a single type
 19
 20namespace Azure.Storage.Blobs.Specialized
 21{
 22    /// <summary>
 23    /// The <see cref="BlobBaseClient"/> allows you to manipulate Azure Storage
 24    /// blobs.
 25    /// </summary>
 26    public class BlobBaseClient
 27    {
 28        /// <summary>
 29        /// The blob's primary <see cref="Uri"/> endpoint.
 30        /// </summary>
 31        private readonly Uri _uri;
 32
 33        /// <summary>
 34        /// Gets the blob's primary <see cref="Uri"/> endpoint.
 35        /// </summary>
 36        public virtual Uri Uri => _uri;
 37
 38        /// <summary>
 39        /// The <see cref="HttpPipeline"/> transport pipeline used to send
 40        /// every request.
 41        /// </summary>
 42        private readonly HttpPipeline _pipeline;
 43
 44        /// <summary>
 45        /// The <see cref="HttpPipeline"/> transport pipeline used to send
 46        /// every request.
 47        /// </summary>
 48        internal virtual HttpPipeline Pipeline => _pipeline;
 49
 50        /// <summary>
 51        /// The version of the service to use when sending requests.
 52        /// </summary>
 53        private readonly BlobClientOptions.ServiceVersion _version;
 54
 55        /// <summary>
 56        /// The version of the service to use when sending requests.
 57        /// </summary>
 58        internal virtual BlobClientOptions.ServiceVersion Version => _version;
 59
 60        /// <summary>
 61        /// The <see cref="ClientDiagnostics"/> instance used to create diagnostic scopes
 62        /// every request.
 63        /// </summary>
 64        private readonly ClientDiagnostics _clientDiagnostics;
 65
 66        /// <summary>
 67        /// The <see cref="ClientDiagnostics"/> instance used to create diagnostic scopes
 68        /// every request.
 69        /// </summary>
 70        internal virtual ClientDiagnostics ClientDiagnostics => _clientDiagnostics;
 71
 72        /// <summary>
 73        /// The <see cref="CustomerProvidedKey"/> to be used when sending requests.
 74        /// </summary>
 75        internal readonly CustomerProvidedKey? _customerProvidedKey;
 76
 77        /// <summary>
 78        /// The <see cref="CustomerProvidedKey"/> to be used when sending requests.
 79        /// </summary>
 80        internal virtual CustomerProvidedKey? CustomerProvidedKey => _customerProvidedKey;
 81
 82        /// <summary>
 83        /// The <see cref="ClientSideEncryptionOptions"/> to be used when sending/receiving requests.
 84        /// </summary>
 85        private readonly ClientSideEncryptionOptions _clientSideEncryption;
 86
 87        /// <summary>
 88        /// The <see cref="ClientSideEncryptionOptions"/> to be used when sending/receiving requests.
 89        /// </summary>
 90        internal virtual ClientSideEncryptionOptions ClientSideEncryption => _clientSideEncryption;
 91
 92        internal bool UsingClientSideEncryption => ClientSideEncryption != default;
 93
 94        /// <summary>
 95        /// The name of the Encryption Scope to be used when sending requests.
 96        /// </summary>
 97        internal readonly string _encryptionScope;
 98
 99        /// <summary>
 100        /// The name of the Encryption Scope to be used when sending requests.
 101        /// </summary>
 102        internal virtual string EncryptionScope => _encryptionScope;
 103
 104        /// <summary>
 105        /// The Storage account name corresponding to the blob client.
 106        /// </summary>
 107        private string _accountName;
 108
 109        /// <summary>
 110        /// Gets the Storage account name corresponding to the blob client.
 111        /// </summary>
 112        public virtual string AccountName
 113        {
 114            get
 115            {
 116                SetNameFieldsIfNull();
 117                return _accountName;
 118            }
 119        }
 120
 121        /// <summary>
 122        /// The container name corresponding to the blob client.
 123        /// </summary>
 124        private string _containerName;
 125
 126        /// <summary>
 127        /// Gets the container name corresponding to the blob client.
 128        /// </summary>
 129        public virtual string BlobContainerName
 130        {
 131            get
 132            {
 133                SetNameFieldsIfNull();
 134                return _containerName;
 135            }
 136        }
 137
 138        /// <summary>
 139        /// The name of the blob.
 140        /// </summary>
 141        private string _name;
 142
 143        /// <summary>
 144        /// Gets the name of the blob.
 145        /// </summary>
 146        public virtual string Name
 147        {
 148            get
 149            {
 150                SetNameFieldsIfNull();
 151                return _name;
 152            }
 153        }
 154
 155        #region ctors
 156        /// <summary>
 157        /// Initializes a new instance of the <see cref="BlobBaseClient"/>
 158        /// class.
 159        /// </summary>
 160        protected BlobBaseClient()
 161        {
 162        }
 163
 164        /// <summary>
 165        /// Initializes a new instance of the <see cref="BlobBaseClient"/>
 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 blob.
 179        /// </param>
 180        /// <param name="blobName">
 181        /// The name of this blob.
 182        /// </param>
 183        public BlobBaseClient(string connectionString, string blobContainerName, string blobName)
 184            : this(connectionString, blobContainerName, blobName, null)
 185        {
 186        }
 187
 188        /// <summary>
 189        /// Initializes a new instance of the <see cref="BlobBaseClient"/>
 190        /// class.
 191        /// </summary>
 192        /// <param name="connectionString">
 193        /// A connection string includes the authentication information
 194        /// required for your application to access data in an Azure Storage
 195        /// account at runtime.
 196        ///
 197        /// For more information,
 198        /// <see href="https://docs.microsoft.com/azure/storage/common/storage-configure-connection-string">
 199        /// Configure Azure Storage connection strings</see>
 200        /// </param>
 201        /// <param name="blobContainerName">
 202        /// The name of the container containing this blob.
 203        /// </param>
 204        /// <param name="blobName">
 205        /// The name of this blob.
 206        /// </param>
 207        /// <param name="options">
 208        /// Optional client options that define the transport pipeline
 209        /// policies for authentication, retries, etc., that are applied to
 210        /// every request.
 211        /// </param>
 212        public BlobBaseClient(string connectionString, string blobContainerName, string blobName, BlobClientOptions opti
 213        {
 214            options ??= new BlobClientOptions();
 215            var conn = StorageConnectionString.Parse(connectionString);
 216            var builder =
 217                new BlobUriBuilder(conn.BlobEndpoint)
 218                {
 219                    BlobContainerName = blobContainerName,
 220                    BlobName = blobName
 221                };
 222            _uri = builder.ToUri();
 223            _pipeline = options.Build(conn.Credentials);
 224            _version = options.Version;
 225            _clientDiagnostics = new ClientDiagnostics(options);
 226            _customerProvidedKey = options.CustomerProvidedKey;
 227            _clientSideEncryption = options._clientSideEncryptionOptions?.Clone();
 228            _encryptionScope = options.EncryptionScope;
 229            BlobErrors.VerifyHttpsCustomerProvidedKey(_uri, _customerProvidedKey);
 230            BlobErrors.VerifyCpkAndEncryptionScopeNotBothSet(_customerProvidedKey, _encryptionScope);
 231        }
 232
 233        /// <summary>
 234        /// Initializes a new instance of the <see cref="BlobBaseClient"/>
 235        /// class.
 236        /// </summary>
 237        /// <param name="blobUri">
 238        /// A <see cref="Uri"/> referencing the blob that includes the
 239        /// name of the account, the name of the container, and the name of
 240        /// the blob.
 241        /// This is likely to be similar to "https://{account_name}.blob.core.windows.net/{container_name}/{blob_name}".
 242        /// </param>
 243        /// <param name="options">
 244        /// Optional client options that define the transport pipeline
 245        /// policies for authentication, retries, etc., that are applied to
 246        /// every request.
 247        /// </param>
 248        public BlobBaseClient(Uri blobUri, BlobClientOptions options = default)
 249            : this(blobUri, (HttpPipelinePolicy)null, options)
 250        {
 251        }
 252
 253        /// <summary>
 254        /// Initializes a new instance of the <see cref="BlobBaseClient"/>
 255        /// class.
 256        /// </summary>
 257        /// <param name="blobUri">
 258        /// A <see cref="Uri"/> referencing the blob that includes the
 259        /// name of the account, the name of the container, and the name of
 260        /// the blob.
 261        /// This is likely to be similar to "https://{account_name}.blob.core.windows.net/{container_name}/{blob_name}".
 262        /// </param>
 263        /// <param name="credential">
 264        /// The shared key credential used to sign requests.
 265        /// </param>
 266        /// <param name="options">
 267        /// Optional client options that define the transport pipeline
 268        /// policies for authentication, retries, etc., that are applied to
 269        /// every request.
 270        /// </param>
 271        public BlobBaseClient(Uri blobUri, StorageSharedKeyCredential credential, BlobClientOptions options = default)
 272            : this(blobUri, credential.AsPolicy(), options)
 273        {
 274        }
 275
 276        /// <summary>
 277        /// Initializes a new instance of the <see cref="BlobBaseClient"/>
 278        /// class.
 279        /// </summary>
 280        /// <param name="blobUri">
 281        /// A <see cref="Uri"/> referencing the blob that includes the
 282        /// name of the account, the name of the container, and the name of
 283        /// the blob.
 284        /// This is likely to be similar to "https://{account_name}.blob.core.windows.net/{container_name}/{blob_name}".
 285        /// </param>
 286        /// <param name="credential">
 287        /// The token credential used to sign requests.
 288        /// </param>
 289        /// <param name="options">
 290        /// Optional client options that define the transport pipeline
 291        /// policies for authentication, retries, etc., that are applied to
 292        /// every request.
 293        /// </param>
 294        public BlobBaseClient(Uri blobUri, TokenCredential credential, BlobClientOptions options = default)
 295            : this(blobUri, credential.AsPolicy(), options)
 296        {
 297            Errors.VerifyHttpsTokenAuth(blobUri);
 298        }
 299
 300        /// <summary>
 301        /// Initializes a new instance of the <see cref="BlobBaseClient"/>
 302        /// class.
 303        /// </summary>
 304        /// <param name="blobUri">
 305        /// A <see cref="Uri"/> referencing the blob that includes the
 306        /// name of the account, the name of the container, and the name of
 307        /// the blob.
 308        /// This is likely to be similar to "https://{account_name}.blob.core.windows.net/{container_name}/{blob_name}".
 309        /// </param>
 310        /// <param name="authentication">
 311        /// An optional authentication policy used to sign requests.
 312        /// </param>
 313        /// <param name="options">
 314        /// Optional client options that define the transport pipeline
 315        /// policies for authentication, retries, etc., that are applied to
 316        /// every request.
 317        /// </param>
 318        internal BlobBaseClient(Uri blobUri, HttpPipelinePolicy authentication, BlobClientOptions options)
 319        {
 320            options ??= new BlobClientOptions();
 321            _uri = blobUri;
 322            _pipeline = options.Build(authentication);
 323            _version = options.Version;
 324            _clientDiagnostics = new ClientDiagnostics(options);
 325            _customerProvidedKey = options.CustomerProvidedKey;
 326            _clientSideEncryption = options._clientSideEncryptionOptions?.Clone();
 327            _encryptionScope = options.EncryptionScope;
 328            BlobErrors.VerifyHttpsCustomerProvidedKey(_uri, _customerProvidedKey);
 329            BlobErrors.VerifyCpkAndEncryptionScopeNotBothSet(_customerProvidedKey, _encryptionScope);
 330        }
 331
 332        /// <summary>
 333        /// Initializes a new instance of the <see cref="BlobBaseClient"/>
 334        /// class.
 335        /// </summary>
 336        /// <param name="blobUri">
 337        /// A <see cref="Uri"/> referencing the blob that includes the
 338        /// name of the account, the name of the container, and the name of
 339        /// the blob.
 340        /// This is likely to be similar to "https://{account_name}.blob.core.windows.net/{container_name}/{blob_name}".
 341        /// </param>
 342        /// <param name="pipeline">
 343        /// The transport pipeline used to send every request.
 344        /// </param>
 345        /// <param name="version">
 346        /// The version of the service to use when sending requests.
 347        /// </param>
 348        /// <param name="clientDiagnostics">Client diagnostics.</param>
 349        /// <param name="customerProvidedKey">Customer provided key.</param>
 350        /// <param name="clientSideEncryption">Client-side encryption options.</param>
 351        /// <param name="encryptionScope">Encryption scope.</param>
 352        internal BlobBaseClient(
 353            Uri blobUri,
 354            HttpPipeline pipeline,
 355            BlobClientOptions.ServiceVersion version,
 356            ClientDiagnostics clientDiagnostics,
 357            CustomerProvidedKey? customerProvidedKey,
 358            ClientSideEncryptionOptions clientSideEncryption,
 359            string encryptionScope)
 360        {
 361            _uri = blobUri;
 362            _pipeline = pipeline;
 363            _version = version;
 364            _clientDiagnostics = clientDiagnostics;
 365            _customerProvidedKey = customerProvidedKey;
 366            _clientSideEncryption = clientSideEncryption?.Clone();
 367            _encryptionScope = encryptionScope;
 368            BlobErrors.VerifyHttpsCustomerProvidedKey(_uri, _customerProvidedKey);
 369            BlobErrors.VerifyCpkAndEncryptionScopeNotBothSet(_customerProvidedKey, _encryptionScope);
 370        }
 371        #endregion ctors
 372
 373        /// <summary>
 374        /// Initializes a new instance of the <see cref="BlobBaseClient"/>
 375        /// class with an identical <see cref="Uri"/> source but the specified
 376        /// <paramref name="snapshot"/> timestamp.
 377        ///
 378        /// For more information, see
 379        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/creating-a-snapshot-of-a-blob">
 380        /// Create a snapshot of a blob</see>.
 381        /// </summary>
 382        /// <param name="snapshot">The snapshot identifier.</param>
 383        /// <returns>A new <see cref="BlobBaseClient"/> instance.</returns>
 384        /// <remarks>
 385        /// Pass null or empty string to remove the snapshot returning a URL
 386        /// to the base blob.
 387        /// </remarks>
 388        public virtual BlobBaseClient WithSnapshot(string snapshot) => WithSnapshotCore(snapshot);
 389
 390        /// <summary>
 391        /// Creates a new instance of the <see cref="BlobBaseClient"/> class
 392        /// with an identical <see cref="Uri"/> source but the specified
 393        /// <paramref name="snapshot"/> timestamp.
 394        /// </summary>
 395        /// <param name="snapshot">The snapshot identifier.</param>
 396        /// <returns>A new <see cref="BlobBaseClient"/> instance.</returns>
 397        protected virtual BlobBaseClient WithSnapshotCore(string snapshot)
 398        {
 399            var blobUriBuilder = new BlobUriBuilder(Uri)
 400            {
 401                Snapshot = snapshot
 402            };
 403
 404            return new BlobBaseClient(
 405                blobUriBuilder.ToUri(),
 406                Pipeline,
 407                Version,
 408                ClientDiagnostics,
 409                CustomerProvidedKey,
 410                ClientSideEncryption,
 411                EncryptionScope);
 412        }
 413
 414        /// <summary>
 415        /// Initializes a new instance of the <see cref="BlobBaseClient"/>
 416        /// class with an identical <see cref="Uri"/> source but the specified
 417        /// <paramref name="versionId"/> timestamp.
 418        ///
 419        /// </summary>
 420        /// <param name="versionId">The version identifier.</param>
 421        /// <returns>A new <see cref="BlobBaseClient"/> instance.</returns>
 422        /// <remarks>
 423        /// Pass null or empty string to remove the version returning a URL
 424        /// to the base blob.
 425        /// </remarks>
 426        public virtual BlobBaseClient WithVersion(string versionId) => WithVersionCore(versionId);
 427
 428        /// <summary>
 429        /// Creates a new instance of the <see cref="BlobBaseClient"/> class
 430        /// with an identical <see cref="Uri"/> source but the specified
 431        /// <paramref name="versionId"/> timestamp.
 432        /// </summary>
 433        /// <param name="versionId">The version identifier.</param>
 434        /// <returns>A new <see cref="BlobBaseClient"/> instance.</returns>
 435        private protected virtual BlobBaseClient WithVersionCore(string versionId)
 436        {
 437            BlobUriBuilder blobUriBuilder = new BlobUriBuilder(Uri)
 438            {
 439                VersionId = versionId
 440            };
 441
 442            return new BlobBaseClient(
 443                blobUriBuilder.ToUri(),
 444                Pipeline,
 445                Version,
 446                ClientDiagnostics,
 447                CustomerProvidedKey,
 448                ClientSideEncryption,
 449                EncryptionScope);
 450        }
 451
 452        /// <summary>
 453        /// Sets the various name fields if they are currently null.
 454        /// </summary>
 455        private void SetNameFieldsIfNull()
 456        {
 457            if (_name == null || _containerName == null || _accountName == null)
 458            {
 459                var builder = new BlobUriBuilder(Uri);
 460                _name = builder.BlobName;
 461                _containerName = builder.BlobContainerName;
 462                _accountName = builder.AccountName;
 463            }
 464        }
 465
 466        ///// <summary>
 467        ///// Creates a clone of this instance that references a version ID rather than the base blob.
 468        ///// </summary>
 469        ///// /// <remarks>
 470        ///// Pass null or empty string to remove the version ID returning a URL to the base blob.
 471        ///// </remarks>
 472        ///// <param name="versionId">The version ID to use on this blob. An empty string or null indicates to use the b
 473        ///// <returns>The new <see cref="BlobBaseClient"/> instance referencing the versionId.</returns>
 474        //public virtual BlobBaseClient WithVersionId(string versionId) => this.WithVersionIdImpl(versionId);
 475
 476        //protected virtual BlobBaseClient WithVersionIdImpl(string versionId)
 477        //{
 478        //    var builder = new BlobUriBuilder(this.Uri)
 479        //    {
 480        //        VersionId = versionId
 481        //    };
 482        //    return new BlobUri(builder.ToUri(), this.Pipeline);
 483        //}
 484
 485        #region Download
 486        /// <summary>
 487        /// The <see cref="Download()"/> operation downloads a blob from
 488        /// the service, including its metadata and properties.
 489        ///
 490        /// For more information, see
 491        /// <see href="https://docs.microsoft.com/rest/api/storageservices/get-blob">
 492        /// Get Blob</see>.
 493        /// </summary>
 494        /// <returns>
 495        /// A <see cref="Response{BlobDownloadInfo}"/> describing the
 496        /// downloaded blob.  <see cref="BlobDownloadInfo.Content"/> contains
 497        /// the blob's data.
 498        /// </returns>
 499        /// <remarks>
 500        /// A <see cref="RequestFailedException"/> will be thrown if
 501        /// a failure occurs.
 502        /// </remarks>
 503        public virtual Response<BlobDownloadInfo> Download() =>
 504            Download(CancellationToken.None);
 505
 506        /// <summary>
 507        /// The <see cref="DownloadAsync()"/> operation downloads a blob from
 508        /// the service, including its metadata and properties.
 509        ///
 510        /// For more information, see
 511        /// <see href="https://docs.microsoft.com/rest/api/storageservices/get-blob">
 512        /// Get Blob</see>.
 513        /// </summary>
 514        /// <returns>
 515        /// A <see cref="Response{BlobDownloadInfo}"/> describing the
 516        /// downloaded blob.  <see cref="BlobDownloadInfo.Content"/> contains
 517        /// the blob's data.
 518        /// </returns>
 519        /// <remarks>
 520        /// A <see cref="RequestFailedException"/> will be thrown if
 521        /// a failure occurs.
 522        /// </remarks>
 523        public virtual async Task<Response<BlobDownloadInfo>> DownloadAsync() =>
 524            await DownloadAsync(CancellationToken.None).ConfigureAwait(false);
 525
 526        /// <summary>
 527        /// The <see cref="Download(CancellationToken)"/> operation downloads
 528        /// a blob from the service, including its metadata and properties.
 529        ///
 530        /// For more information, see
 531        /// <see href="https://docs.microsoft.com/rest/api/storageservices/get-blob">
 532        /// Get Blob</see>.
 533        /// </summary>
 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{BlobDownloadInfo}"/> describing the
 540        /// downloaded blob.  <see cref="BlobDownloadInfo.Content"/> contains
 541        /// the blob's data.
 542        /// </returns>
 543        /// <remarks>
 544        /// A <see cref="RequestFailedException"/> will be thrown if
 545        /// a failure occurs.
 546        /// </remarks>
 547        public virtual Response<BlobDownloadInfo> Download(
 548            CancellationToken cancellationToken = default) =>
 549            Download(
 550                conditions: default, // Pass anything else so we don't recurse on this overload
 551                cancellationToken: cancellationToken);
 552
 553        /// <summary>
 554        /// The <see cref="DownloadAsync(CancellationToken)"/> operation
 555        /// downloads a blob from the service, including its metadata and
 556        /// properties.
 557        ///
 558        /// For more information, see
 559        /// <see href="https://docs.microsoft.com/rest/api/storageservices/get-blob">
 560        /// Get Blob</see>.
 561        /// </summary>
 562        /// <param name="cancellationToken">
 563        /// Optional <see cref="CancellationToken"/> to propagate
 564        /// notifications that the operation should be cancelled.
 565        /// </param>
 566        /// <returns>
 567        /// A <see cref="Response{BlobDownloadInfo}"/> describing the
 568        /// downloaded blob.  <see cref="BlobDownloadInfo.Content"/> contains
 569        /// the blob's data.
 570        /// </returns>
 571        /// <remarks>
 572        /// A <see cref="RequestFailedException"/> will be thrown if
 573        /// a failure occurs.
 574        /// </remarks>
 575        public virtual async Task<Response<BlobDownloadInfo>> DownloadAsync(
 576            CancellationToken cancellationToken) =>
 577            await DownloadAsync(
 578                conditions: default, // Pass anything else so we don't recurse on this overload
 579                cancellationToken: cancellationToken)
 580                .ConfigureAwait(false);
 581
 582        /// <summary>
 583        /// The <see cref="Download(HttpRange, BlobRequestConditions, bool, CancellationToken)"/>
 584        /// operation downloads a blob from the service, including its metadata
 585        /// and properties.
 586        ///
 587        /// For more information, see
 588        /// <see href="https://docs.microsoft.com/rest/api/storageservices/get-blob">
 589        /// Get Blob</see>.
 590        /// </summary>
 591        /// <param name="range">
 592        /// If provided, only download the bytes of the blob in the specified
 593        /// range.  If not provided, download the entire blob.
 594        /// </param>
 595        /// <param name="conditions">
 596        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
 597        /// downloading this blob.
 598        /// </param>
 599        /// <param name="rangeGetContentHash">
 600        /// When set to true and specified together with the <paramref name="range"/>,
 601        /// the service returns the MD5 hash for the range, as long as the
 602        /// range is less than or equal to 4 MB in size.  If this value is
 603        /// specified without <paramref name="range"/> or set to true when the
 604        /// range exceeds 4 MB in size, a <see cref="RequestFailedException"/>
 605        /// is thrown.
 606        /// </param>
 607        /// <param name="cancellationToken">
 608        /// Optional <see cref="CancellationToken"/> to propagate
 609        /// notifications that the operation should be cancelled.
 610        /// </param>
 611        /// <returns>
 612        /// A <see cref="Response{BlobDownloadInfo}"/> describing the
 613        /// downloaded blob.  <see cref="BlobDownloadInfo.Content"/> contains
 614        /// the blob's data.
 615        /// </returns>
 616        /// <remarks>
 617        /// A <see cref="RequestFailedException"/> will be thrown if
 618        /// a failure occurs.
 619        /// </remarks>
 620        public virtual Response<BlobDownloadInfo> Download(
 621            HttpRange range = default,
 622            BlobRequestConditions conditions = default,
 623            bool rangeGetContentHash = default,
 624            CancellationToken cancellationToken = default) =>
 625            DownloadInternal(
 626                range,
 627                conditions,
 628                rangeGetContentHash,
 629                false, // async
 630                cancellationToken)
 631                .EnsureCompleted();
 632
 633        /// <summary>
 634        /// The <see cref="DownloadAsync(HttpRange, BlobRequestConditions, bool, CancellationToken)"/>
 635        /// operation downloads a blob from the service, including its metadata
 636        /// and properties.
 637        ///
 638        /// For more information, see
 639        /// <see href="https://docs.microsoft.com/rest/api/storageservices/get-blob">
 640        /// Get Blob</see>.
 641        /// </summary>
 642        /// <param name="range">
 643        /// If provided, only download the bytes of the blob in the specified
 644        /// range.  If not provided, download the entire blob.
 645        /// </param>
 646        /// <param name="conditions">
 647        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
 648        /// downloading this blob.
 649        /// </param>
 650        /// <param name="rangeGetContentHash">
 651        /// When set to true and specified together with the <paramref name="range"/>,
 652        /// the service returns the MD5 hash for the range, as long as the
 653        /// range is less than or equal to 4 MB in size.  If this value is
 654        /// specified without <paramref name="range"/> or set to true when the
 655        /// range exceeds 4 MB in size, a <see cref="RequestFailedException"/>
 656        /// is thrown.
 657        /// </param>
 658        /// <param name="cancellationToken">
 659        /// Optional <see cref="CancellationToken"/> to propagate
 660        /// notifications that the operation should be cancelled.
 661        /// </param>
 662        /// <returns>
 663        /// A <see cref="Response{BlobDownloadInfo}"/> describing the
 664        /// downloaded blob.  <see cref="BlobDownloadInfo.Content"/> contains
 665        /// the blob's data.
 666        /// </returns>
 667        /// <remarks>
 668        /// A <see cref="RequestFailedException"/> will be thrown if
 669        /// a failure occurs.
 670        /// </remarks>
 671        public virtual async Task<Response<BlobDownloadInfo>> DownloadAsync(
 672            HttpRange range = default,
 673            BlobRequestConditions conditions = default,
 674            bool rangeGetContentHash = default,
 675            CancellationToken cancellationToken = default) =>
 676            await DownloadInternal(
 677                range,
 678                conditions,
 679                rangeGetContentHash,
 680                true, // async
 681                cancellationToken)
 682                .ConfigureAwait(false);
 683
 684        /// <summary>
 685        /// The <see cref="DownloadInternal"/> operation downloads a blob
 686        /// from the service, including its metadata and properties.
 687        ///
 688        /// For more information, see
 689        /// <see href="https://docs.microsoft.com/rest/api/storageservices/get-blob">
 690        /// Get Blob</see>.
 691        /// </summary>
 692        /// <param name="range">
 693        /// If provided, only download the bytes of the blob in the specified
 694        /// range.  If not provided, download the entire blob.
 695        /// </param>
 696        /// <param name="conditions">
 697        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
 698        /// downloading this blob.
 699        /// </param>
 700        /// <param name="rangeGetContentHash">
 701        /// When set to true and specified together with the <paramref name="range"/>,
 702        /// the service returns the MD5 hash for the range, as long as the
 703        /// range is less than or equal to 4 MB in size.  If this value is
 704        /// specified without <paramref name="range"/> or set to true when the
 705        /// range exceeds 4 MB in size, a <see cref="RequestFailedException"/>
 706        /// is thrown.
 707        /// </param>
 708        /// <param name="async">
 709        /// Whether to invoke the operation asynchronously.
 710        /// </param>
 711        /// <param name="cancellationToken">
 712        /// Optional <see cref="CancellationToken"/> to propagate
 713        /// notifications that the operation should be cancelled.
 714        /// </param>
 715        /// <returns>
 716        /// A <see cref="Response{BlobDownloadInfo}"/> describing the
 717        /// downloaded blob.  <see cref="BlobDownloadInfo.Content"/> contains
 718        /// the blob's data.
 719        /// </returns>
 720        /// <remarks>
 721        /// A <see cref="RequestFailedException"/> will be thrown if
 722        /// a failure occurs.
 723        /// </remarks>
 724        private async Task<Response<BlobDownloadInfo>> DownloadInternal(
 725            HttpRange range,
 726            BlobRequestConditions conditions,
 727            bool rangeGetContentHash,
 728            bool async,
 729            CancellationToken cancellationToken)
 730        {
 731            HttpRange requestedRange = range;
 732            using (Pipeline.BeginLoggingScope(nameof(BlobBaseClient)))
 733            {
 734                Pipeline.LogMethodEnter(nameof(BlobBaseClient), message: $"{nameof(Uri)}: {Uri}");
 735                try
 736                {
 737                    if (UsingClientSideEncryption)
 738                    {
 739                        range = BlobClientSideDecryptor.GetEncryptedBlobRange(range);
 740                    }
 741
 742                    // Start downloading the blob
 743                    (Response<FlattenedDownloadProperties> response, Stream stream) = await StartDownloadAsync(
 744                        range,
 745                        conditions,
 746                        rangeGetContentHash,
 747                        async: async,
 748                        cancellationToken: cancellationToken)
 749                        .ConfigureAwait(false);
 750
 751                    // Return an exploding Response on 304
 752                    if (response.IsUnavailable())
 753                    {
 754                        return response.GetRawResponse().AsNoBodyResponse<BlobDownloadInfo>();
 755                    }
 756
 757                    // Wrap the response Content in a RetriableStream so we
 758                    // can return it before it's finished downloading, but still
 759                    // allow retrying if it fails.
 760                    stream = RetriableStream.Create(
 761                        stream,
 762                         startOffset =>
 763                            StartDownloadAsync(
 764                                    range,
 765                                    conditions,
 766                                    rangeGetContentHash,
 767                                    startOffset,
 768                                    async,
 769                                    cancellationToken)
 770                                .EnsureCompleted()
 771                            .Item2,
 772                        async startOffset =>
 773                            (await StartDownloadAsync(
 774                                range,
 775                                conditions,
 776                                rangeGetContentHash,
 777                                startOffset,
 778                                async,
 779                                cancellationToken)
 780                                .ConfigureAwait(false))
 781                            .Item2,
 782                        Pipeline.ResponseClassifier,
 783                        Constants.MaxReliabilityRetries);
 784
 785                    // if using clientside encryption, wrap the auto-retry stream in a decryptor
 786                    // we already return a nonseekable stream; returning a crypto stream is fine
 787                    if (UsingClientSideEncryption)
 788                    {
 789                        stream = await new BlobClientSideDecryptor(new ClientSideDecryptor(ClientSideEncryption))
 790                            .DecryptInternal(stream, response.Value.Metadata, requestedRange, response.Value.ContentRang
 791                    }
 792
 793                    response.Value.Content = stream;
 794
 795                    // Wrap the FlattenedDownloadProperties into a BlobDownloadOperation
 796                    // to make the Content easier to find
 797                    return Response.FromValue(new BlobDownloadInfo(response.Value), response.GetRawResponse());
 798                }
 799                catch (Exception ex)
 800                {
 801                    Pipeline.LogException(ex);
 802                    throw;
 803                }
 804                finally
 805                {
 806                    Pipeline.LogMethodExit(nameof(BlobBaseClient));
 807                }
 808            }
 809        }
 810
 811        /// <summary>
 812        /// The <see cref="StartDownloadAsync"/> operation starts downloading
 813        /// a blob from the service from a given <paramref name="startOffset"/>.
 814        /// </summary>
 815        /// <param name="range">
 816        /// If provided, only download the bytes of the blob in the specified
 817        /// range.  If not provided, download the entire blob.
 818        /// </param>
 819        /// <param name="conditions">
 820        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
 821        /// downloading this blob.
 822        /// </param>
 823        /// <param name="rangeGetContentHash">
 824        /// When set to true and specified together with the <paramref name="range"/>,
 825        /// the service returns the MD5 hash for the range, as long as the
 826        /// range is less than or equal to 4 MB in size.  If this value is
 827        /// specified without <paramref name="range"/> or set to true when the
 828        /// range exceeds 4 MB in size, a <see cref="RequestFailedException"/>
 829        /// is thrown.
 830        /// </param>
 831        /// <param name="startOffset">
 832        /// Starting offset to request - in the event of a retry.
 833        /// </param>
 834        /// <param name="async">
 835        /// Whether to invoke the operation asynchronously.
 836        /// </param>
 837        /// <param name="cancellationToken">
 838        /// Optional <see cref="CancellationToken"/> to propagate
 839        /// notifications that the operation should be cancelled.
 840        /// </param>
 841        /// <returns>
 842        /// A <see cref="Response{BlobDownloadInfo}"/> describing the
 843        /// downloaded blob.  <see cref="BlobDownloadInfo.Content"/> contains
 844        /// the blob's data.
 845        /// </returns>
 846        /// <remarks>
 847        /// A <see cref="RequestFailedException"/> will be thrown if
 848        /// a failure occurs.
 849        /// </remarks>
 850        private async Task<(Response<FlattenedDownloadProperties>, Stream)> StartDownloadAsync(
 851            HttpRange range = default,
 852            BlobRequestConditions conditions = default,
 853            bool rangeGetContentHash = default,
 854            long startOffset = 0,
 855            bool async = true,
 856            CancellationToken cancellationToken = default)
 857        {
 858            HttpRange? pageRange = null;
 859            if (range != default || startOffset != 0)
 860            {
 861                pageRange = new HttpRange(
 862                    range.Offset + startOffset,
 863                    range.Length.HasValue ?
 864                        range.Length.Value - startOffset :
 865                        (long?)null);
 866            }
 867
 868            Pipeline.LogTrace($"Download {Uri} with range: {pageRange}");
 869
 870            (Response<FlattenedDownloadProperties> response, Stream stream) =
 871                await BlobRestClient.Blob.DownloadAsync(
 872                    ClientDiagnostics,
 873                    Pipeline,
 874                    Uri,
 875                    version: Version.ToVersionString(),
 876                    range: pageRange?.ToString(),
 877                    leaseId: conditions?.LeaseId,
 878                    rangeGetContentHash: rangeGetContentHash ? (bool?)true : null,
 879                    encryptionKey: CustomerProvidedKey?.EncryptionKey,
 880                    encryptionKeySha256: CustomerProvidedKey?.EncryptionKeyHash,
 881                    encryptionAlgorithm: CustomerProvidedKey?.EncryptionAlgorithm,
 882                    ifModifiedSince: conditions?.IfModifiedSince,
 883                    ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
 884                    ifMatch: conditions?.IfMatch,
 885                    ifNoneMatch: conditions?.IfNoneMatch,
 886                    ifTags: conditions?.TagConditions,
 887                    async: async,
 888                    operationName: "BlobBaseClient.Download",
 889                    cancellationToken: cancellationToken)
 890                    .ConfigureAwait(false);
 891
 892            // Watch out for exploding Responses
 893            long length = response.IsUnavailable() ? 0 : response.Value.ContentLength;
 894            Pipeline.LogTrace($"Response: {response.GetRawResponse().Status}, ContentLength: {length}");
 895
 896            return (response, stream);
 897        }
 898        #endregion Download
 899
 900        #region Parallel Download
 901        /// <summary>
 902        /// The <see cref="DownloadTo(Stream)"/> operation downloads a blob using parallel requests,
 903        /// and writes the content to <paramref name="destination"/>.
 904        /// </summary>
 905        /// <param name="destination">
 906        /// A <see cref="Stream"/> to write the downloaded content to.
 907        /// </param>
 908        /// <returns>
 909        /// A <see cref="Response"/> describing the operation.
 910        /// </returns>
 911        /// <remarks>
 912        /// A <see cref="RequestFailedException"/> will be thrown if
 913        /// a failure occurs.
 914        /// </remarks>
 915        public virtual Response DownloadTo(Stream destination) =>
 916            DownloadTo(destination, CancellationToken.None);
 917
 918        /// <summary>
 919        /// The <see cref="DownloadTo(string)"/> operation downloads a blob using parallel requests,
 920        /// and writes the content to <paramref name="path"/>.
 921        /// </summary>
 922        /// <param name="path">
 923        /// A file path to write the downloaded content to.
 924        /// </param>
 925        /// <returns>
 926        /// A <see cref="Response"/> describing the operation.
 927        /// </returns>
 928        /// <remarks>
 929        /// A <see cref="RequestFailedException"/> will be thrown if
 930        /// a failure occurs.
 931        /// </remarks>
 932        public virtual Response DownloadTo(string path) =>
 933            DownloadTo(path, CancellationToken.None);
 934
 935        /// <summary>
 936        /// The <see cref="DownloadToAsync(Stream)"/> downloads a blob using parallel requests,
 937        /// and writes the content to <paramref name="destination"/>.
 938        /// </summary>
 939        /// <param name="destination">
 940        /// A <see cref="Stream"/> to write the downloaded content to.
 941        /// </param>
 942        /// <returns>
 943        /// A <see cref="Response"/> describing the operation.
 944        /// </returns>
 945        /// <remarks>
 946        /// A <see cref="RequestFailedException"/> will be thrown if
 947        /// a failure occurs.
 948        /// </remarks>
 949        public virtual async Task<Response> DownloadToAsync(Stream destination) =>
 950            await DownloadToAsync(destination, CancellationToken.None).ConfigureAwait(false);
 951
 952        /// <summary>
 953        /// The <see cref="DownloadToAsync(string)"/> downloads a blob using parallel requests,
 954        /// and writes the content to <paramref name="path"/>.
 955        /// </summary>
 956        /// <param name="path">
 957        /// A file path to write the downloaded content to.
 958        /// </param>
 959        /// <returns>
 960        /// A <see cref="Response"/> describing the operation.
 961        /// </returns>
 962        /// <remarks>
 963        /// A <see cref="RequestFailedException"/> will be thrown if
 964        /// a failure occurs.
 965        /// </remarks>
 966        public virtual async Task<Response> DownloadToAsync(string path) =>
 967            await DownloadToAsync(path, CancellationToken.None).ConfigureAwait(false);
 968
 969        /// <summary>
 970        /// The <see cref="DownloadTo(Stream, CancellationToken)"/> operation
 971        /// downloads a blob using parallel requests,
 972        /// and writes the content to <paramref name="destination"/>.
 973        /// </summary>
 974        /// <param name="destination">
 975        /// A <see cref="Stream"/> to write the downloaded content to.
 976        /// </param>
 977        /// <param name="cancellationToken">
 978        /// Optional <see cref="CancellationToken"/> to propagate
 979        /// notifications that the operation should be cancelled.
 980        /// </param>
 981        /// <returns>
 982        /// A <see cref="Response"/> describing the operation.
 983        /// </returns>
 984        /// <remarks>
 985        /// A <see cref="RequestFailedException"/> will be thrown if
 986        /// a failure occurs.
 987        /// </remarks>
 988        public virtual Response DownloadTo(
 989            Stream destination,
 990            CancellationToken cancellationToken) =>
 991            DownloadTo(
 992                destination,
 993                conditions: default, // Pass anything else so we don't recurse on this overload
 994                cancellationToken: cancellationToken);
 995
 996        /// <summary>
 997        /// The <see cref="DownloadTo(string, CancellationToken)"/> operation
 998        /// downloads a blob using parallel requests,
 999        /// and writes the content to <paramref name="path"/>.
 1000        /// </summary>
 1001        /// <param name="path">
 1002        /// A file path to write the downloaded content to.
 1003        /// </param>
 1004        /// <param name="cancellationToken">
 1005        /// Optional <see cref="CancellationToken"/> to propagate
 1006        /// notifications that the operation should be cancelled.
 1007        /// </param>
 1008        /// <returns>
 1009        /// A <see cref="Response"/> describing the operation.
 1010        /// </returns>
 1011        /// <remarks>
 1012        /// A <see cref="RequestFailedException"/> will be thrown if
 1013        /// a failure occurs.
 1014        /// </remarks>
 1015        public virtual Response DownloadTo(
 1016            string path,
 1017            CancellationToken cancellationToken) =>
 1018            DownloadTo(
 1019                path,
 1020                conditions: default, // Pass anything else so we don't recurse on this overload
 1021                cancellationToken: cancellationToken);
 1022
 1023        /// <summary>
 1024        /// The <see cref="DownloadToAsync(Stream, CancellationToken)"/> operation
 1025        /// downloads a blob using parallel requests,
 1026        /// and writes the content to <paramref name="destination"/>.
 1027        /// </summary>
 1028        /// <param name="destination">
 1029        /// A <see cref="Stream"/> to write the downloaded content to.
 1030        /// </param>
 1031        /// <param name="cancellationToken">
 1032        /// Optional <see cref="CancellationToken"/> to propagate
 1033        /// notifications that the operation should be cancelled.
 1034        /// </param>
 1035        /// <returns>
 1036        /// A <see cref="Response"/> describing the operation.
 1037        /// </returns>
 1038        /// <remarks>
 1039        /// A <see cref="RequestFailedException"/> will be thrown if
 1040        /// a failure occurs.
 1041        /// </remarks>
 1042        public virtual async Task<Response> DownloadToAsync(
 1043            Stream destination,
 1044            CancellationToken cancellationToken) =>
 1045            await DownloadToAsync(
 1046                destination,
 1047                conditions: default, // Pass anything else so we don't recurse on this overload
 1048                cancellationToken: cancellationToken)
 1049                .ConfigureAwait(false);
 1050
 1051        /// <summary>
 1052        /// The <see cref="DownloadToAsync(string, CancellationToken)"/> operation
 1053        /// downloads a blob using parallel requests,
 1054        /// and writes the content to <paramref name="path"/>.
 1055        /// </summary>
 1056        /// <param name="path">
 1057        /// A file path to write the downloaded content to.
 1058        /// </param>
 1059        /// <param name="cancellationToken">
 1060        /// Optional <see cref="CancellationToken"/> to propagate
 1061        /// notifications that the operation should be cancelled.
 1062        /// </param>
 1063        /// <returns>
 1064        /// A <see cref="Response"/> describing the operation.
 1065        /// </returns>
 1066        /// <remarks>
 1067        /// A <see cref="RequestFailedException"/> will be thrown if
 1068        /// a failure occurs.
 1069        /// </remarks>
 1070        public virtual async Task<Response> DownloadToAsync(
 1071            string path,
 1072            CancellationToken cancellationToken) =>
 1073            await DownloadToAsync(
 1074                path,
 1075                conditions: default, // Pass anything else so we don't recurse on this overload
 1076                cancellationToken: cancellationToken)
 1077                .ConfigureAwait(false);
 1078
 1079        /// <summary>
 1080        /// The <see cref="DownloadTo(Stream, BlobRequestConditions, StorageTransferOptions, CancellationToken)"/>
 1081        /// operation downloads a blob using parallel requests,
 1082        /// and writes the content to <paramref name="destination"/>.
 1083        /// </summary>
 1084        /// <param name="destination">
 1085        /// A <see cref="Stream"/> to write the downloaded content to.
 1086        /// </param>
 1087        /// <param name="conditions">
 1088        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
 1089        /// the creation of this new block blob.
 1090        /// </param>
 1091        /// <param name="transferOptions">
 1092        /// Optional <see cref="StorageTransferOptions"/> to configure
 1093        /// parallel transfer behavior.
 1094        /// </param>
 1095        /// <param name="cancellationToken">
 1096        /// Optional <see cref="CancellationToken"/> to propagate
 1097        /// notifications that the operation should be cancelled.
 1098        /// </param>
 1099        /// <returns>
 1100        /// A <see cref="Response"/> describing the operation.
 1101        /// </returns>
 1102        /// <remarks>
 1103        /// A <see cref="RequestFailedException"/> will be thrown if
 1104        /// a failure occurs.
 1105        /// </remarks>
 1106        public virtual Response DownloadTo(
 1107            Stream destination,
 1108            BlobRequestConditions conditions = default,
 1109            ///// <param name="progressHandler">
 1110            ///// Optional <see cref="IProgress{Long}"/> to provide
 1111            ///// progress updates about data transfers.
 1112            ///// </param>
 1113            //IProgress<long> progressHandler = default,
 1114            StorageTransferOptions transferOptions = default,
 1115            CancellationToken cancellationToken = default) =>
 1116            StagedDownloadAsync(
 1117                destination,
 1118                conditions,
 1119                //progressHandler, // TODO: #8506
 1120                transferOptions: transferOptions,
 1121                async: false,
 1122                cancellationToken: cancellationToken)
 1123                .EnsureCompleted();
 1124
 1125        /// <summary>
 1126        /// The <see cref="DownloadTo(string, BlobRequestConditions, StorageTransferOptions, CancellationToken)"/>
 1127        /// operation downloads a blob using parallel requests,
 1128        /// and writes the content to <paramref name="path"/>.
 1129        /// </summary>
 1130        /// <param name="path">
 1131        /// A file path to write the downloaded content to.
 1132        /// </param>
 1133        /// <param name="conditions">
 1134        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
 1135        /// the creation of this new block blob.
 1136        /// </param>
 1137        /// <param name="transferOptions">
 1138        /// Optional <see cref="StorageTransferOptions"/> to configure
 1139        /// parallel transfer behavior.
 1140        /// </param>
 1141        /// <param name="cancellationToken">
 1142        /// Optional <see cref="CancellationToken"/> to propagate
 1143        /// notifications that the operation should be cancelled.
 1144        /// </param>
 1145        /// <returns>
 1146        /// A <see cref="Response"/> describing the operation.
 1147        /// </returns>
 1148        /// <remarks>
 1149        /// A <see cref="RequestFailedException"/> will be thrown if
 1150        /// a failure occurs.
 1151        /// </remarks>
 1152        public virtual Response DownloadTo(
 1153            string path,
 1154            BlobRequestConditions conditions = default,
 1155            ///// <param name="progressHandler">
 1156            ///// Optional <see cref="IProgress{Long}"/> to provide
 1157            ///// progress updates about data transfers.
 1158            ///// </param>
 1159            //IProgress<long> progressHandler = default,
 1160            StorageTransferOptions transferOptions = default,
 1161            CancellationToken cancellationToken = default)
 1162        {
 1163            using Stream destination = File.Create(path);
 1164            return StagedDownloadAsync(
 1165                destination,
 1166                conditions,
 1167                //progressHandler, // TODO: #8506
 1168                transferOptions: transferOptions,
 1169                async: false,
 1170                cancellationToken: cancellationToken)
 1171                .EnsureCompleted();
 1172        }
 1173
 1174        /// <summary>
 1175        /// The <see cref="DownloadToAsync(Stream, BlobRequestConditions, StorageTransferOptions, CancellationToken)"/>
 1176        /// operation downloads a blob using parallel requests,
 1177        /// and writes the content to <paramref name="destination"/>.
 1178        /// </summary>
 1179        /// <param name="destination">
 1180        /// A <see cref="Stream"/> to write the downloaded content to.
 1181        /// </param>
 1182        /// <param name="conditions">
 1183        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
 1184        /// the creation of this new block blob.
 1185        /// </param>
 1186        /// <param name="transferOptions">
 1187        /// Optional <see cref="StorageTransferOptions"/> to configure
 1188        /// parallel transfer behavior.
 1189        /// </param>
 1190        /// <param name="cancellationToken">
 1191        /// Optional <see cref="CancellationToken"/> to propagate
 1192        /// notifications that the operation should be cancelled.
 1193        /// </param>
 1194        /// <returns>
 1195        /// A <see cref="Response"/> describing the operation.
 1196        /// </returns>
 1197        /// <remarks>
 1198        /// A <see cref="RequestFailedException"/> will be thrown if
 1199        /// a failure occurs.
 1200        /// </remarks>
 1201        public virtual async Task<Response> DownloadToAsync(
 1202            Stream destination,
 1203            BlobRequestConditions conditions = default,
 1204            ///// <param name="progressHandler">
 1205            ///// Optional <see cref="IProgress{Long}"/> to provide
 1206            ///// progress updates about data transfers.
 1207            ///// </param>
 1208            //IProgress<long> progressHandler = default,
 1209            StorageTransferOptions transferOptions = default,
 1210            CancellationToken cancellationToken = default) =>
 1211            await StagedDownloadAsync(
 1212                destination,
 1213                conditions,
 1214                //progressHandler, // TODO: #8506
 1215                transferOptions: transferOptions,
 1216                async: true,
 1217                cancellationToken: cancellationToken)
 1218                .ConfigureAwait(false);
 1219
 1220        /// <summary>
 1221        /// The <see cref="DownloadToAsync(string, BlobRequestConditions, StorageTransferOptions, CancellationToken)"/>
 1222        /// operation downloads a blob using parallel requests,
 1223        /// and writes the content to <paramref name="path"/>.
 1224        /// </summary>
 1225        /// <param name="path">
 1226        /// A file path to write the downloaded content to.
 1227        /// </param>
 1228        /// <param name="conditions">
 1229        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
 1230        /// the creation of this new block blob.
 1231        /// </param>
 1232        /// <param name="transferOptions">
 1233        /// Optional <see cref="StorageTransferOptions"/> to configure
 1234        /// parallel transfer behavior.
 1235        /// </param>
 1236        /// <param name="cancellationToken">
 1237        /// Optional <see cref="CancellationToken"/> to propagate
 1238        /// notifications that the operation should be cancelled.
 1239        /// </param>
 1240        /// <returns>
 1241        /// A <see cref="Response"/> describing the operation.
 1242        /// </returns>
 1243        /// <remarks>
 1244        /// A <see cref="RequestFailedException"/> will be thrown if
 1245        /// a failure occurs.
 1246        /// </remarks>
 1247        public virtual async Task<Response> DownloadToAsync(
 1248            string path,
 1249            BlobRequestConditions conditions = default,
 1250            ///// <param name="progressHandler">
 1251            ///// Optional <see cref="IProgress{Long}"/> to provide
 1252            ///// progress updates about data transfers.
 1253            ///// </param>
 1254            //IProgress<long> progressHandler = default,
 1255            StorageTransferOptions transferOptions = default,
 1256            CancellationToken cancellationToken = default)
 1257        {
 1258            using Stream destination = File.Create(path);
 1259            return await StagedDownloadAsync(
 1260                destination,
 1261                conditions,
 1262                //progressHandler, // TODO: #8506
 1263                transferOptions: transferOptions,
 1264                async: true,
 1265                cancellationToken: cancellationToken)
 1266                .ConfigureAwait(false);
 1267        }
 1268
 1269        /// <summary>
 1270        /// This operation will download a blob of arbitrary size by downloading it as individually staged
 1271        /// partitions if it's larger than the
 1272        /// <paramref name="transferOptions"/> MaximumTransferLength.
 1273        /// </summary>
 1274        /// <param name="destination">
 1275        /// A <see cref="Stream"/> to write the downloaded content to.
 1276        /// </param>
 1277        /// <param name="conditions">
 1278        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
 1279        /// the creation of this new block blob.
 1280        /// </param>
 1281        /// <param name="transferOptions">
 1282        /// Optional <see cref="StorageTransferOptions"/> to configure
 1283        /// parallel transfer behavior.
 1284        /// </param>
 1285        /// <param name="async">
 1286        /// Whether to invoke the operation asynchronously.
 1287        /// </param>
 1288        /// <param name="cancellationToken">
 1289        /// Optional <see cref="CancellationToken"/> to propagate
 1290        /// notifications that the operation should be cancelled.
 1291        /// </param>
 1292        /// <returns>
 1293        /// A <see cref="Response"/> describing the operation.
 1294        /// </returns>
 1295        /// <remarks>
 1296        /// A <see cref="RequestFailedException"/> will be thrown if
 1297        /// a failure occurs.
 1298        /// </remarks>
 1299        internal async Task<Response> StagedDownloadAsync(
 1300            Stream destination,
 1301            BlobRequestConditions conditions = default,
 1302            ///// <param name="progressHandler">
 1303            ///// Optional <see cref="IProgress{Long}"/> to provide
 1304            ///// progress updates about data transfers.
 1305            ///// </param>
 1306            //IProgress<long> progressHandler, // TODO: #8506
 1307            StorageTransferOptions transferOptions = default,
 1308            bool async = true,
 1309            CancellationToken cancellationToken = default)
 1310        {
 1311            var client = new BlobBaseClient(Uri, Pipeline, Version, ClientDiagnostics, CustomerProvidedKey, ClientSideEn
 1312
 1313            PartitionedDownloader downloader = new PartitionedDownloader(client, transferOptions);
 1314
 1315            if (async)
 1316            {
 1317                return await downloader.DownloadToAsync(destination, conditions, cancellationToken).ConfigureAwait(false
 1318            }
 1319            else
 1320            {
 1321                return downloader.DownloadTo(destination, conditions, cancellationToken);
 1322            }
 1323        }
 1324        #endregion Parallel Download
 1325
 1326        #region OpenRead
 1327        /// <summary>
 1328        /// Opens a stream for reading from the blob.  The stream will only download
 1329        /// the blob as the stream is read from.
 1330        /// </summary>
 1331        /// <param name="position">
 1332        /// The position within the blob to begin the stream.
 1333        /// Defaults to the beginning of the blob.
 1334        /// </param>
 1335        /// <param name="bufferSize">
 1336        /// The buffer size to use when the stream downloads parts
 1337        /// of the blob.  Defaults to 1 MB.
 1338        /// </param>
 1339        /// <param name="conditions">
 1340        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
 1341        /// the download of the blob.
 1342        /// </param>
 1343        /// <param name="cancellationToken">
 1344        /// Optional <see cref="CancellationToken"/> to propagate
 1345        /// notifications that the operation should be cancelled.
 1346        /// </param>
 1347        /// <returns>
 1348        /// Returns a stream that will download the blob as the stream
 1349        /// is read from.
 1350        /// </returns>
 1351#pragma warning disable AZC0015 // Unexpected client method return type.
 1352        public virtual Stream OpenRead(
 1353#pragma warning restore AZC0015 // Unexpected client method return type.
 1354            long position = 0,
 1355            int? bufferSize = default,
 1356            BlobRequestConditions conditions = default,
 1357            CancellationToken cancellationToken = default)
 1358            => OpenReadInternal(
 1359                position,
 1360                bufferSize,
 1361                conditions,
 1362                async: false,
 1363                cancellationToken).EnsureCompleted();
 1364
 1365        /// <summary>
 1366        /// Opens a stream for reading from the blob.  The stream will only download
 1367        /// the blob as the stream is read from.
 1368        /// </summary>
 1369        /// <param name="allowBlobModifications">
 1370        /// If true, you can continue streaming a blob even if it has been modified.
 1371        /// </param>
 1372        /// <param name="position">
 1373        /// The position within the blob to begin the stream.
 1374        /// Defaults to the beginning of the blob.
 1375        /// </param>
 1376        /// <param name="bufferSize">
 1377        /// The buffer size to use when the stream downloads parts
 1378        /// of the blob.  Defaults to 1 MB.
 1379        /// </param>
 1380        /// <param name="cancellationToken">
 1381        /// Optional <see cref="CancellationToken"/> to propagate
 1382        /// notifications that the operation should be cancelled.
 1383        /// </param>
 1384        /// <returns>
 1385        /// Returns a stream that will download the blob as the stream
 1386        /// is read from.
 1387        /// </returns>
 1388#pragma warning disable AZC0015 // Unexpected client method return type.
 1389        public virtual Stream OpenRead(
 1390#pragma warning restore AZC0015 // Unexpected client method return type.
 1391            bool allowBlobModifications,
 1392            long position = 0,
 1393            int? bufferSize = default,
 1394            CancellationToken cancellationToken = default)
 1395                => OpenRead(
 1396                    position,
 1397                    bufferSize,
 1398                    allowBlobModifications ? new BlobRequestConditions() : null,
 1399                    cancellationToken);
 1400
 1401        /// <summary>
 1402        /// Opens a stream for reading from the blob.  The stream will only download
 1403        /// the blob as the stream is read from.
 1404        /// </summary>
 1405        /// <param name="position">
 1406        /// The position within the blob to begin the stream.
 1407        /// Defaults to the beginning of the blob.
 1408        /// </param>
 1409        /// <param name="bufferSize">
 1410        /// The buffer size to use when the stream downloads parts
 1411        /// of the blob.  Defaults to 1 MB.
 1412        /// </param>
 1413        /// <param name="conditions">
 1414        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
 1415        /// the download of the blob.
 1416        /// </param>
 1417        /// <param name="cancellationToken">
 1418        /// Optional <see cref="CancellationToken"/> to propagate
 1419        /// notifications that the operation should be cancelled.
 1420        /// </param>
 1421        /// <returns>
 1422        /// Returns a stream that will download the blob as the stream
 1423        /// is read from.
 1424        /// </returns>
 1425#pragma warning disable AZC0015 // Unexpected client method return type.
 1426        public virtual async Task<Stream> OpenReadAsync(
 1427#pragma warning restore AZC0015 // Unexpected client method return type.
 1428            long position = 0,
 1429            int? bufferSize = default,
 1430            BlobRequestConditions conditions = default,
 1431            CancellationToken cancellationToken = default)
 1432            => await OpenReadInternal(
 1433                position,
 1434                bufferSize,
 1435                conditions,
 1436                async: true,
 1437                cancellationToken).ConfigureAwait(false);
 1438
 1439        /// <summary>
 1440        /// Opens a stream for reading from the blob.  The stream will only download
 1441        /// the blob as the stream is read from.
 1442        /// </summary>
 1443        /// <param name="allowBlobModifications">
 1444        /// If true, you can continue streaming a blob even if it has been modified.
 1445        /// </param>
 1446        /// <param name="position">
 1447        /// The position within the blob to begin the stream.
 1448        /// Defaults to the beginning of the blob.
 1449        /// </param>
 1450        /// <param name="bufferSize">
 1451        /// The buffer size to use when the stream downloads parts
 1452        /// of the blob.  Defaults to 1 MB.
 1453        /// </param>
 1454        /// <param name="cancellationToken">
 1455        /// Optional <see cref="CancellationToken"/> to propagate
 1456        /// notifications that the operation should be cancelled.
 1457        /// </param>
 1458        /// <returns>
 1459        /// Returns a stream that will download the blob as the stream
 1460        /// is read from.
 1461        /// </returns>
 1462#pragma warning disable AZC0015 // Unexpected client method return type.
 1463        public virtual async Task<Stream> OpenReadAsync(
 1464#pragma warning restore AZC0015 // Unexpected client method return type.
 1465            bool allowBlobModifications,
 1466            long position = 0,
 1467            int? bufferSize = default,
 1468            CancellationToken cancellationToken = default)
 1469                => await OpenReadAsync(
 1470                    position,
 1471                    bufferSize,
 1472                    allowBlobModifications ? new BlobRequestConditions() : null,
 1473                    cancellationToken)
 1474                    .ConfigureAwait(false);
 1475
 1476        /// <summary>
 1477        /// Opens a stream for reading from the blob.  The stream will only download
 1478        /// the blob as the stream is read from.
 1479        /// </summary>
 1480        /// <param name="position">
 1481        /// The position within the blob to begin the stream.
 1482        /// Defaults to the beginning of the blob.
 1483        /// </param>
 1484        /// <param name="bufferSize">
 1485        /// The buffer size to use when the stream downloads parts
 1486        /// of the blob.  Defaults to 1 MB.
 1487        /// </param>
 1488        /// <param name="conditions">
 1489        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
 1490        /// the download of the blob.
 1491        /// </param>
 1492        /// <param name="async">
 1493        /// Whether to invoke the operation asynchronously.
 1494        /// </param>
 1495        /// <param name="cancellationToken">
 1496        /// Optional <see cref="CancellationToken"/> to propagate
 1497        /// notifications that the operation should be cancelled.
 1498        /// </param>
 1499        /// <returns>
 1500        /// Returns a stream that will download the blob as the stream
 1501        /// is read from.
 1502        /// </returns>
 1503#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
 1504        internal async Task<Stream> OpenReadInternal(
 1505#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
 1506            long position,
 1507            int? bufferSize,
 1508            BlobRequestConditions conditions,
 1509#pragma warning disable CA1801
 1510            bool async,
 1511            CancellationToken cancellationToken)
 1512#pragma warning restore CA1801
 1513        {
 1514            using (Pipeline.BeginLoggingScope(nameof(BlobBaseClient)))
 1515            {
 1516                Pipeline.LogMethodEnter(
 1517                nameof(BlobBaseClient),
 1518                message:
 1519                $"{nameof(position)}: {position}\n" +
 1520                $"{nameof(bufferSize)}: {bufferSize}\n" +
 1521                $"{nameof(conditions)}: {conditions}");
 1522
 1523                DiagnosticScope scope = ClientDiagnostics.CreateScope($"{nameof(BlobBaseClient)}.{nameof(OpenRead)}");
 1524                try
 1525                {
 1526                    scope.Start();
 1527
 1528                    return new LazyLoadingReadOnlyStream<BlobRequestConditions, BlobProperties>(
 1529                        async (HttpRange range,
 1530                        BlobRequestConditions conditions,
 1531                        bool rangeGetContentHash,
 1532                        bool async,
 1533                        CancellationToken cancellationToken) =>
 1534                        {
 1535                            Response<BlobDownloadInfo> response = await DownloadInternal(
 1536                                range,
 1537                                conditions,
 1538                                rangeGetContentHash,
 1539                                async,
 1540                                cancellationToken).ConfigureAwait(false);
 1541
 1542                            return Response.FromValue(
 1543                                (IDownloadedContent)response.Value,
 1544                                response.GetRawResponse());
 1545                        },
 1546                        (ETag? eTag) => new BlobRequestConditions { IfMatch = eTag },
 1547                        async (bool async, CancellationToken cancellationToken)
 1548                            => await GetPropertiesInternal(conditions: default, async, cancellationToken).ConfigureAwait
 1549                        position,
 1550                        bufferSize,
 1551                        conditions);
 1552                }
 1553                catch (Exception ex)
 1554                {
 1555                    scope.Failed(ex);
 1556                    Pipeline.LogException(ex);
 1557                    throw;
 1558                }
 1559                finally
 1560                {
 1561                    scope.Dispose();
 1562                    Pipeline.LogMethodExit(nameof(BlobContainerClient));
 1563                }
 1564            }
 1565        }
 1566
 1567        #endregion OpenRead
 1568
 1569        #region StartCopyFromUri
 1570        /// <summary>
 1571        /// The <see cref="StartCopyFromUri(Uri, BlobCopyFromUriOptions, CancellationToken)"/>
 1572        /// operation begins an asynchronous copy of the data from the <paramref name="source"/> to this blob.
 1573        /// You can check the <see cref="BlobProperties.CopyStatus"/>
 1574        /// returned from the <see cref="GetProperties"/> to determine if the
 1575        /// copy has completed.
 1576        ///
 1577        /// For more information, see
 1578        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/copy-blob">
 1579        /// Copy Blob</see>.
 1580        /// </summary>
 1581        /// <param name="source">
 1582        /// Specifies the <see cref="Uri"/> of the source blob.  The value may
 1583        /// be a <see cref="Uri" /> of up to 2 KB in length that specifies a
 1584        /// blob.  A source blob in the same storage account can be
 1585        /// authenticated via Shared Key.  However, if the source is a blob in
 1586        /// another account, the source blob must either be public or must be
 1587        /// authenticated via a shared access signature. If the source blob
 1588        /// is public, no authentication is required to perform the copy
 1589        /// operation.
 1590        ///
 1591        /// The source object may be a file in the Azure File service.  If the
 1592        /// source object is a file that is to be copied to a blob, then the
 1593        /// source file must be authenticated using a shared access signature,
 1594        /// whether it resides in the same account or in a different account.
 1595        /// </param>
 1596        /// <param name="options">
 1597        /// Optional parameters.
 1598        /// </param>
 1599        /// <param name="cancellationToken">
 1600        /// Optional <see cref="CancellationToken"/> to propagate
 1601        /// notifications that the operation should be cancelled.
 1602        /// </param>
 1603        /// <returns>
 1604        /// A <see cref="CopyFromUriOperation"/> describing the
 1605        /// state of the copy operation.
 1606        /// </returns>
 1607        /// <remarks>
 1608        /// A <see cref="RequestFailedException"/> will be thrown if
 1609        /// a failure occurs.
 1610        /// </remarks>
 1611        public virtual CopyFromUriOperation StartCopyFromUri(
 1612            Uri source,
 1613            BlobCopyFromUriOptions options,
 1614            CancellationToken cancellationToken = default)
 1615        {
 1616            Response<BlobCopyInfo> response = StartCopyFromUriInternal(
 1617                source,
 1618                options?.Metadata,
 1619                options?.Tags,
 1620                options?.AccessTier,
 1621                options?.SourceConditions,
 1622                options?.DestinationConditions,
 1623                options?.RehydratePriority,
 1624                options?.ShouldSealDestination,
 1625                async: false,
 1626                cancellationToken)
 1627                .EnsureCompleted();
 1628            return new CopyFromUriOperation(
 1629                this,
 1630                response.Value.CopyId,
 1631                response.GetRawResponse(),
 1632                cancellationToken);
 1633        }
 1634
 1635        /// <summary>
 1636        /// The <see cref="StartCopyFromUri(Uri, Metadata, AccessTier?, BlobRequestConditions, BlobRequestConditions, Re
 1637        /// operation begins an asynchronous copy of the data from the <paramref name="source"/> to this blob.
 1638        /// You can check the <see cref="BlobProperties.CopyStatus"/>
 1639        /// returned from the <see cref="GetProperties"/> to determine if the
 1640        /// copy has completed.
 1641        ///
 1642        /// For more information, see
 1643        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/copy-blob">
 1644        /// Copy Blob</see>.
 1645        /// </summary>
 1646        /// <param name="source">
 1647        /// Specifies the <see cref="Uri"/> of the source blob.  The value may
 1648        /// be a <see cref="Uri" /> of up to 2 KB in length that specifies a
 1649        /// blob.  A source blob in the same storage account can be
 1650        /// authenticated via Shared Key.  However, if the source is a blob in
 1651        /// another account, the source blob must either be public or must be
 1652        /// authenticated via a shared access signature. If the source blob
 1653        /// is public, no authentication is required to perform the copy
 1654        /// operation.
 1655        ///
 1656        /// The source object may be a file in the Azure File service.  If the
 1657        /// source object is a file that is to be copied to a blob, then the
 1658        /// source file must be authenticated using a shared access signature,
 1659        /// whether it resides in the same account or in a different account.
 1660        /// </param>
 1661        /// <param name="metadata">
 1662        /// Optional custom metadata to set for this blob.
 1663        /// </param>
 1664        /// <param name="accessTier">
 1665        /// Optional <see cref="AccessTier"/>
 1666        /// Indicates the tier to be set on the blob.
 1667        /// </param>
 1668        /// <param name="sourceConditions">
 1669        /// Optional <see cref="BlobRequestConditions"/> to add
 1670        /// conditions on the copying of data from this source blob.
 1671        /// </param>
 1672        /// <param name="destinationConditions">
 1673        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
 1674        /// the copying of data to this blob.
 1675        /// </param>
 1676        /// <param name="rehydratePriority">
 1677        /// Optional <see cref="RehydratePriority"/>
 1678        /// Indicates the priority with which to rehydrate an archived blob.
 1679        /// </param>
 1680        /// <param name="cancellationToken">
 1681        /// Optional <see cref="CancellationToken"/> to propagate
 1682        /// notifications that the operation should be cancelled.
 1683        /// </param>
 1684        /// <returns>
 1685        /// A <see cref="CopyFromUriOperation"/> describing the
 1686        /// state of the copy operation.
 1687        /// </returns>
 1688        /// <remarks>
 1689        /// A <see cref="RequestFailedException"/> will be thrown if
 1690        /// a failure occurs.
 1691        /// </remarks>
 1692        [EditorBrowsable(EditorBrowsableState.Never)]
 1693        public virtual CopyFromUriOperation StartCopyFromUri(
 1694            Uri source,
 1695            Metadata metadata = default,
 1696            AccessTier? accessTier = default,
 1697            BlobRequestConditions sourceConditions = default,
 1698            BlobRequestConditions destinationConditions = default,
 1699            RehydratePriority? rehydratePriority = default,
 1700            CancellationToken cancellationToken = default)
 1701        {
 1702            Response<BlobCopyInfo> response = StartCopyFromUriInternal(
 1703                source,
 1704                metadata,
 1705                default,
 1706                accessTier,
 1707                sourceConditions,
 1708                destinationConditions,
 1709                rehydratePriority,
 1710                sealBlob: default,
 1711                async: false,
 1712                cancellationToken)
 1713                .EnsureCompleted();
 1714            return new CopyFromUriOperation(
 1715                this,
 1716                response.Value.CopyId,
 1717                response.GetRawResponse(),
 1718                cancellationToken);
 1719        }
 1720
 1721        /// <summary>
 1722        /// The <see cref="StartCopyFromUri(Uri, Metadata, AccessTier?, BlobRequestConditions, BlobRequestConditions, Re
 1723        /// operation begins an asynchronous copy of the data from the <paramref name="source"/>
 1724        /// to this blob.  You can check the <see cref="BlobProperties.CopyStatus"/>
 1725        /// returned from the <see cref="GetPropertiesAsync"/> to determine if
 1726        /// the copy has completed.
 1727        ///
 1728        /// For more information, see
 1729        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/copy-blob">
 1730        /// Copy Blob</see>.
 1731        /// </summary>
 1732        /// <param name="source">
 1733        /// Specifies the <see cref="Uri"/> of the source blob.  The value may
 1734        /// be a <see cref="Uri" /> of up to 2 KB in length that specifies a
 1735        /// blob.  A source blob in the same storage account can be
 1736        /// authenticated via Shared Key.  However, if the source is a blob in
 1737        /// another account, the source blob must either be public or must be
 1738        /// authenticated via a shared access signature. If the source blob
 1739        /// is public, no authentication is required to perform the copy
 1740        /// operation.
 1741        ///
 1742        /// The source object may be a file in the Azure File service.  If the
 1743        /// source object is a file that is to be copied to a blob, then the
 1744        /// source file must be authenticated using a shared access signature,
 1745        /// whether it resides in the same account or in a different account.
 1746        /// </param>
 1747        /// <param name="options">
 1748        /// Optional parameters.
 1749        /// </param>
 1750        /// <param name="cancellationToken">
 1751        /// Optional <see cref="CancellationToken"/> to propagate
 1752        /// notifications that the operation should be cancelled.
 1753        /// </param>
 1754        /// <returns>
 1755        /// A <see cref="CopyFromUriOperation"/> describing the
 1756        /// state of the copy operation.
 1757        /// </returns>
 1758        /// <remarks>
 1759        /// A <see cref="RequestFailedException"/> will be thrown if
 1760        /// a failure occurs.
 1761        /// </remarks>
 1762        public virtual async Task<CopyFromUriOperation> StartCopyFromUriAsync(
 1763            Uri source,
 1764            BlobCopyFromUriOptions options,
 1765            CancellationToken cancellationToken = default)
 1766        {
 1767            Response<BlobCopyInfo> response = await StartCopyFromUriInternal(
 1768                source,
 1769                options?.Metadata,
 1770                options?.Tags,
 1771                options?.AccessTier,
 1772                options?.SourceConditions,
 1773                options?.DestinationConditions,
 1774                options?.RehydratePriority,
 1775                options?.ShouldSealDestination,
 1776                async: true,
 1777                cancellationToken)
 1778                .ConfigureAwait(false);
 1779            return new CopyFromUriOperation(
 1780                this,
 1781                response.Value.CopyId,
 1782                response.GetRawResponse(),
 1783                cancellationToken);
 1784        }
 1785
 1786        /// <summary>
 1787        /// The <see cref="StartCopyFromUri(Uri, Metadata, AccessTier?, BlobRequestConditions, BlobRequestConditions, Re
 1788        /// operation begins an asynchronous copy of the data from the <paramref name="source"/>
 1789        /// to this blob.You can check the <see cref="BlobProperties.CopyStatus"/>
 1790        /// returned from the <see cref="GetPropertiesAsync"/> to determine if
 1791        /// the copy has completed.
 1792        ///
 1793        /// For more information, see
 1794        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/copy-blob">
 1795        /// Copy Blob</see>.
 1796        /// </summary>
 1797        /// <param name="source">
 1798        /// Specifies the <see cref="Uri"/> of the source blob.  The value may
 1799        /// be a <see cref="Uri" /> of up to 2 KB in length that specifies a
 1800        /// blob.  A source blob in the same storage account can be
 1801        /// authenticated via Shared Key.  However, if the source is a blob in
 1802        /// another account, the source blob must either be public or must be
 1803        /// authenticated via a shared access signature. If the source blob
 1804        /// is public, no authentication is required to perform the copy
 1805        /// operation.
 1806        ///
 1807        /// The source object may be a file in the Azure File service.  If the
 1808        /// source object is a file that is to be copied to a blob, then the
 1809        /// source file must be authenticated using a shared access signature,
 1810        /// whether it resides in the same account or in a different account.
 1811        /// </param>
 1812        /// <param name="metadata">
 1813        /// Optional custom metadata to set for this blob.
 1814        /// </param>
 1815        /// <param name="accessTier">
 1816        /// Optional <see cref="AccessTier"/>
 1817        /// Indicates the tier to be set on the blob.
 1818        /// </param>
 1819        /// <param name="sourceConditions">
 1820        /// Optional <see cref="BlobRequestConditions"/> to add
 1821        /// conditions on the copying of data from this source blob.
 1822        /// </param>
 1823        /// <param name="destinationConditions">
 1824        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
 1825        /// the copying of data to this blob.
 1826        /// </param>
 1827        /// <param name="rehydratePriority">
 1828        /// Optional <see cref="RehydratePriority"/>
 1829        /// Indicates the priority with which to rehydrate an archived blob.
 1830        /// </param>
 1831        /// <param name="cancellationToken">
 1832        /// Optional <see cref="CancellationToken"/> to propagate
 1833        /// notifications that the operation should be cancelled.
 1834        /// </param>
 1835        /// <returns>
 1836        /// A <see cref="CopyFromUriOperation"/> describing the
 1837        /// state of the copy operation.
 1838        /// </returns>
 1839        /// <remarks>
 1840        /// A <see cref="RequestFailedException"/> will be thrown if
 1841        /// a failure occurs.
 1842        /// </remarks>
 1843        [EditorBrowsable(EditorBrowsableState.Never)]
 1844        public virtual async Task<CopyFromUriOperation> StartCopyFromUriAsync(
 1845            Uri source,
 1846            Metadata metadata = default,
 1847            AccessTier? accessTier = default,
 1848            BlobRequestConditions sourceConditions = default,
 1849            BlobRequestConditions destinationConditions = default,
 1850            RehydratePriority? rehydratePriority = default,
 1851            CancellationToken cancellationToken = default)
 1852        {
 1853            Response<BlobCopyInfo> response = await StartCopyFromUriInternal(
 1854                source,
 1855                metadata,
 1856                default,
 1857                accessTier,
 1858                sourceConditions,
 1859                destinationConditions,
 1860                rehydratePriority,
 1861                sealBlob: default,
 1862                async: true,
 1863                cancellationToken)
 1864                .ConfigureAwait(false);
 1865            return new CopyFromUriOperation(
 1866                this,
 1867                response.Value.CopyId,
 1868                response.GetRawResponse(),
 1869                cancellationToken);
 1870        }
 1871
 1872        /// <summary>
 1873        /// The <see cref="StartCopyFromUriInternal"/> operation begins an
 1874        /// asynchronous copy of the data from the <paramref name="source"/>
 1875        /// to this blob.  You can check <see cref="BlobProperties.CopyStatus"/>
 1876        /// returned from the<see cref="GetPropertiesAsync"/> to determine if
 1877        /// the copy has completed.
 1878        ///
 1879        /// For more information, see
 1880        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/copy-blob">
 1881        /// Copy Blob</see>.
 1882        /// </summary>
 1883        /// <param name="source">
 1884        /// Specifies the <see cref="Uri"/> of the source blob.  The value may
 1885        /// be a <see cref="Uri" /> of up to 2 KB in length that specifies a
 1886        /// blob.  A source blob in the same storage account can be
 1887        /// authenticated via Shared Key.  However, if the source is a blob in
 1888        /// another account, the source blob must either be public or must be
 1889        /// authenticated via a shared access signature. If the source blob
 1890        /// is public, no authentication is required to perform the copy
 1891        /// operation.
 1892        ///
 1893        /// The source object may be a file in the Azure File service.  If the
 1894        /// source object is a file that is to be copied to a blob, then the
 1895        /// source file must be authenticated using a shared access signature,
 1896        /// whether it resides in the same account or in a different account.
 1897        /// </param>
 1898        /// <param name="metadata">
 1899        /// Optional custom metadata to set for this blob.
 1900        /// </param>
 1901        /// <param name="tags">
 1902        /// Optional tags to set for this blob.
 1903        /// </param>
 1904        /// <param name="accessTier">
 1905        /// Optional <see cref="AccessTier"/>
 1906        /// Indicates the tier to be set on the blob.
 1907        /// </param>
 1908        /// <param name="sourceConditions">
 1909        /// Optional <see cref="BlobRequestConditions"/> to add
 1910        /// conditions on the copying of data from this source blob.
 1911        /// </param>
 1912        /// <param name="destinationConditions">
 1913        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
 1914        /// the copying of data to this blob.
 1915        /// </param>
 1916        /// <param name="rehydratePriority">
 1917        /// Optional <see cref="RehydratePriority"/>
 1918        /// Indicates the priority with which to rehydrate an archived blob.
 1919        /// </param>
 1920        /// <param name="sealBlob">
 1921        /// If the destination blob should be sealed.
 1922        /// Only applicable for Append Blobs.
 1923        /// </param>
 1924        /// <param name="async">
 1925        /// Whether to invoke the operation asynchronously.
 1926        /// </param>
 1927        /// <param name="cancellationToken">
 1928        /// Optional <see cref="CancellationToken"/> to propagate
 1929        /// notifications that the operation should be cancelled.
 1930        /// </param>
 1931        /// <returns>
 1932        /// A <see cref="Response{BlobCopyInfo}"/> describing the
 1933        /// state of the copy operation.
 1934        /// </returns>
 1935        /// <remarks>
 1936        /// A <see cref="RequestFailedException"/> will be thrown if
 1937        /// a failure occurs.
 1938        /// </remarks>
 1939        private async Task<Response<BlobCopyInfo>> StartCopyFromUriInternal(
 1940            Uri source,
 1941            Metadata metadata,
 1942            Tags tags,
 1943            AccessTier? accessTier,
 1944            BlobRequestConditions sourceConditions,
 1945            BlobRequestConditions destinationConditions,
 1946            RehydratePriority? rehydratePriority,
 1947            bool? sealBlob,
 1948            bool async,
 1949            CancellationToken cancellationToken)
 1950        {
 1951            using (Pipeline.BeginLoggingScope(nameof(BlobBaseClient)))
 1952            {
 1953                Pipeline.LogMethodEnter(
 1954                    nameof(BlobBaseClient),
 1955                    message:
 1956                    $"{nameof(Uri)}: {Uri}\n" +
 1957                    $"{nameof(source)}: {source}\n" +
 1958                    $"{nameof(sourceConditions)}: {sourceConditions}\n" +
 1959                    $"{nameof(destinationConditions)}: {destinationConditions}");
 1960                try
 1961                {
 1962                    return await BlobRestClient.Blob.StartCopyFromUriAsync(
 1963                        ClientDiagnostics,
 1964                        Pipeline,
 1965                        Uri,
 1966                        copySource: source,
 1967                        version: Version.ToVersionString(),
 1968                        rehydratePriority: rehydratePriority,
 1969                        tier: accessTier,
 1970                        sourceIfModifiedSince: sourceConditions?.IfModifiedSince,
 1971                        sourceIfUnmodifiedSince: sourceConditions?.IfUnmodifiedSince,
 1972                        sourceIfMatch: sourceConditions?.IfMatch,
 1973                        sourceIfNoneMatch: sourceConditions?.IfNoneMatch,
 1974                        sourceIfTags: sourceConditions?.TagConditions,
 1975                        ifModifiedSince: destinationConditions?.IfModifiedSince,
 1976                        ifUnmodifiedSince: destinationConditions?.IfUnmodifiedSince,
 1977                        ifMatch: destinationConditions?.IfMatch,
 1978                        ifNoneMatch: destinationConditions?.IfNoneMatch,
 1979                        leaseId: destinationConditions?.LeaseId,
 1980                        ifTags: destinationConditions?.TagConditions,
 1981                        metadata: metadata,
 1982                        blobTagsString: tags?.ToTagsString(),
 1983                        sealBlob: sealBlob,
 1984                        async: async,
 1985                        operationName: $"{nameof(BlobBaseClient)}.{nameof(StartCopyFromUri)}",
 1986                        cancellationToken: cancellationToken)
 1987                        .ConfigureAwait(false);
 1988                }
 1989                catch (Exception ex)
 1990                {
 1991                    Pipeline.LogException(ex);
 1992                    throw;
 1993                }
 1994                finally
 1995                {
 1996                    Pipeline.LogMethodExit(nameof(BlobBaseClient));
 1997                }
 1998            }
 1999        }
 2000        #endregion StartCopyFromUri
 2001
 2002        #region AbortCopyFromUri
 2003        /// <summary>
 2004        /// The <see cref="AbortCopyFromUri"/> operation aborts a pending
 2005        /// <see cref="CopyFromUriOperation"/>, and leaves a this
 2006        /// blob with zero length and full metadata.
 2007        ///
 2008        /// For more information, see
 2009        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/abort-copy-blob">
 2010        /// Abort Copy Blob</see>.
 2011        /// </summary>
 2012        /// <param name="copyId">
 2013        /// ID of the copy operation to abort.
 2014        /// </param>
 2015        /// <param name="conditions">
 2016        /// Optional <see cref="BlobRequestConditions"/> to add
 2017        /// conditions on aborting the copy operation.
 2018        /// </param>
 2019        /// <param name="cancellationToken">
 2020        /// Optional <see cref="CancellationToken"/> to propagate
 2021        /// notifications that the operation should be cancelled.
 2022        /// </param>
 2023        /// <returns>
 2024        /// A <see cref="Response"/> on successfully aborting.
 2025        /// </returns>
 2026        /// <remarks>
 2027        /// A <see cref="RequestFailedException"/> will be thrown if
 2028        /// a failure occurs.
 2029        /// </remarks>
 2030        public virtual Response AbortCopyFromUri(
 2031            string copyId,
 2032            BlobRequestConditions conditions = default,
 2033            CancellationToken cancellationToken = default) =>
 2034            AbortCopyFromUriInternal(
 2035                copyId,
 2036                conditions,
 2037                false, // async
 2038                cancellationToken)
 2039                .EnsureCompleted();
 2040
 2041        /// <summary>
 2042        /// The <see cref="AbortCopyFromUriAsync"/> operation aborts a pending
 2043        /// <see cref="CopyFromUriOperation"/>, and leaves a this
 2044        /// blob with zero length and full metadata.
 2045        ///
 2046        /// For more information, see
 2047        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/abort-copy-blob">
 2048        /// Abort Copy Blob</see>.
 2049        /// </summary>
 2050        /// <param name="copyId">
 2051        /// ID of the copy operation to abort.
 2052        /// </param>
 2053        /// <param name="conditions">
 2054        /// Optional <see cref="BlobRequestConditions"/> to add
 2055        /// conditions on aborting the copy operation.
 2056        /// </param>
 2057        /// <param name="cancellationToken">
 2058        /// Optional <see cref="CancellationToken"/> to propagate
 2059        /// notifications that the operation should be cancelled.
 2060        /// </param>
 2061        /// <returns>
 2062        /// A <see cref="Response"/> on successfully aborting.
 2063        /// </returns>
 2064        /// <remarks>
 2065        /// A <see cref="RequestFailedException"/> will be thrown if
 2066        /// a failure occurs.
 2067        /// </remarks>
 2068        public virtual async Task<Response> AbortCopyFromUriAsync(
 2069            string copyId,
 2070            BlobRequestConditions conditions = default,
 2071            CancellationToken cancellationToken = default) =>
 2072            await AbortCopyFromUriInternal(
 2073                copyId,
 2074                conditions,
 2075                true, // async
 2076                cancellationToken)
 2077                .ConfigureAwait(false);
 2078
 2079        /// <summary>
 2080        /// The <see cref="AbortCopyFromUriAsync"/> operation aborts a pending
 2081        /// <see cref="CopyFromUriOperation"/>, and leaves a this
 2082        /// blob with zero length and full metadata.
 2083        ///
 2084        /// For more information, see
 2085        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/abort-copy-blob">
 2086        /// Abort Copy Blob</see>.
 2087        /// </summary>
 2088        /// <param name="copyId">
 2089        /// ID of the copy operation to abort.
 2090        /// </param>
 2091        /// <param name="conditions">
 2092        /// Optional <see cref="BlobRequestConditions"/> to add
 2093        /// conditions on aborting the copy operation.
 2094        /// </param>
 2095        /// <param name="async">
 2096        /// Whether to invoke the operation asynchronously.
 2097        /// </param>
 2098        /// <param name="cancellationToken">
 2099        /// Optional <see cref="CancellationToken"/> to propagate
 2100        /// notifications that the operation should be cancelled.
 2101        /// </param>
 2102        /// <returns>
 2103        /// A <see cref="Response"/> on successfully aborting.
 2104        /// </returns>
 2105        /// <remarks>
 2106        /// A <see cref="RequestFailedException"/> will be thrown if
 2107        /// a failure occurs.
 2108        /// </remarks>
 2109        private async Task<Response> AbortCopyFromUriInternal(
 2110            string copyId,
 2111            BlobRequestConditions conditions,
 2112            bool async,
 2113            CancellationToken cancellationToken)
 2114        {
 2115            using (Pipeline.BeginLoggingScope(nameof(BlobBaseClient)))
 2116            {
 2117                Pipeline.LogMethodEnter(
 2118                    nameof(BlobBaseClient),
 2119                    message:
 2120                    $"{nameof(Uri)}: {Uri}\n" +
 2121                    $"{nameof(copyId)}: {copyId}\n" +
 2122                    $"{nameof(conditions)}: {conditions}");
 2123                try
 2124                {
 2125                    return await BlobRestClient.Blob.AbortCopyFromUriAsync(
 2126                        ClientDiagnostics,
 2127                        Pipeline,
 2128                        Uri,
 2129                        copyId: copyId,
 2130                        version: Version.ToVersionString(),
 2131                        leaseId: conditions?.LeaseId,
 2132                        async: async,
 2133                        operationName: "BlobBaseClient.AbortCopyFromUri",
 2134                        cancellationToken: cancellationToken)
 2135                        .ConfigureAwait(false);
 2136                }
 2137                catch (Exception ex)
 2138                {
 2139                    Pipeline.LogException(ex);
 2140                    throw;
 2141                }
 2142                finally
 2143                {
 2144                    Pipeline.LogMethodExit(nameof(BlobBaseClient));
 2145                }
 2146            }
 2147        }
 2148        #endregion AbortCopyFromUri
 2149
 2150        #region CopyFromUri
 2151        /// <summary>
 2152        /// The Copy Blob From URL operation copies a blob to a destination within the storage account synchronously
 2153        /// for source blob sizes up to 256 MB. This API is available starting in version 2018-03-28.
 2154        /// The source for a Copy Blob From URL operation can be any committed block blob in any Azure storage account
 2155        /// which is either public or authorized with a shared access signature.
 2156        ///
 2157        /// The size of the source blob can be a maximum length of up to 256 MB.
 2158        ///
 2159        /// For more information, see
 2160        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/copy-blob-from-url">
 2161        /// Copy Blob From URL</see>.
 2162        /// </summary>
 2163        /// <param name="source">
 2164        /// Required. Specifies the URL of the source blob. The value may be a URL of up to 2 KB in length
 2165        /// that specifies a blob. The value should be URL-encoded as it would appear in a request URI. The
 2166        /// source blob must either be public or must be authorized via a shared access signature. If the
 2167        /// source blob is public, no authorization is required to perform the operation. If the size of the
 2168        /// source blob is greater than 256 MB, the request will fail with 409 (Conflict). The blob type of
 2169        /// the source blob has to be block blob.
 2170        /// </param>
 2171        /// <param name="options">
 2172        /// Optional parameters.
 2173        /// </param>
 2174        /// <param name="cancellationToken">
 2175        /// Optional <see cref="CancellationToken"/> to propagate
 2176        /// notifications that the operation should be cancelled.
 2177        /// </param>
 2178        /// <returns>
 2179        /// A <see cref="Response{BlobCopyInfo}"/> describing the
 2180        /// state of the copy operation.
 2181        /// </returns>
 2182        /// <remarks>
 2183        /// A <see cref="RequestFailedException"/> will be thrown if
 2184        /// a failure occurs.
 2185        /// </remarks>
 2186        public virtual Response<BlobCopyInfo> SyncCopyFromUri(
 2187            Uri source,
 2188            BlobCopyFromUriOptions options = default,
 2189            CancellationToken cancellationToken = default)
 2190            => SyncCopyFromUriInternal(
 2191                source: source,
 2192                metadata: options?.Metadata,
 2193                tags: options?.Tags,
 2194                accessTier: options?.AccessTier,
 2195                sourceConditions: options?.SourceConditions,
 2196                destinationConditions: options?.DestinationConditions,
 2197                async: false,
 2198                cancellationToken: cancellationToken)
 2199            .EnsureCompleted();
 2200
 2201        /// <summary>
 2202        /// The Copy Blob From URL operation copies a blob to a destination within the storage account synchronously
 2203        /// for source blob sizes up to 256 MB. This API is available starting in version 2018-03-28.
 2204        /// The source for a Copy Blob From URL operation can be any committed block blob in any Azure storage account
 2205        /// which is either public or authorized with a shared access signature.
 2206        ///
 2207        /// The size of the source blob can be a maximum length of up to 256 MB.
 2208        ///
 2209        /// For more information, see
 2210        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/copy-blob-from-url">
 2211        /// Copy Blob From URL</see>.
 2212        /// </summary>
 2213        /// <param name="source">
 2214        /// Required. Specifies the URL of the source blob. The value may be a URL of up to 2 KB in length
 2215        /// that specifies a blob. The value should be URL-encoded as it would appear in a request URI. The
 2216        /// source blob must either be public or must be authorized via a shared access signature. If the
 2217        /// source blob is public, no authorization is required to perform the operation. If the size of the
 2218        /// source blob is greater than 256 MB, the request will fail with 409 (Conflict). The blob type of
 2219        /// the source blob has to be block blob.
 2220        /// </param>
 2221        /// <param name="options">
 2222        /// Optional parameters.
 2223        /// </param>
 2224        /// <param name="cancellationToken">
 2225        /// Optional <see cref="CancellationToken"/> to propagate
 2226        /// notifications that the operation should be cancelled.
 2227        /// </param>
 2228        /// <returns>
 2229        /// A <see cref="Response{BlobCopyInfo}"/> describing the
 2230        /// state of the copy operation.
 2231        /// </returns>
 2232        /// <remarks>
 2233        /// A <see cref="RequestFailedException"/> will be thrown if
 2234        /// a failure occurs.
 2235        /// </remarks>
 2236        public virtual async Task<Response<BlobCopyInfo>> SyncCopyFromUriAsync(
 2237            Uri source,
 2238            BlobCopyFromUriOptions options = default,
 2239            CancellationToken cancellationToken = default)
 2240            => await SyncCopyFromUriInternal(
 2241                source: source,
 2242                metadata: options?.Metadata,
 2243                tags: options?.Tags,
 2244                accessTier: options?.AccessTier,
 2245                sourceConditions: options?.SourceConditions,
 2246                destinationConditions: options?.DestinationConditions,
 2247                async: true,
 2248                cancellationToken: cancellationToken)
 2249            .ConfigureAwait(false);
 2250
 2251        /// <summary>
 2252        /// The Copy Blob From URL operation copies a blob to a destination within the storage account synchronously
 2253        /// for source blob sizes up to 256 MB. This API is available starting in version 2018-03-28.
 2254        /// The source for a Copy Blob From URL operation can be any committed block blob in any Azure storage account
 2255        /// which is either public or authorized with a shared access signature.
 2256        ///
 2257        /// The size of the source blob can be a maximum length of up to 256 MB.
 2258        ///
 2259        /// For more information, see
 2260        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/copy-blob-from-url">
 2261        /// Copy Blob From URL</see>.
 2262        /// </summary>
 2263        /// <param name="source">
 2264        /// Required. Specifies the URL of the source blob. The value may be a URL of up to 2 KB in length
 2265        /// that specifies a blob. The value should be URL-encoded as it would appear in a request URI. The
 2266        /// source blob must either be public or must be authorized via a shared access signature. If the
 2267        /// source blob is public, no authorization is required to perform the operation. If the size of the
 2268        /// source blob is greater than 256 MB, the request will fail with 409 (Conflict). The blob type of
 2269        /// the source blob has to be block blob.
 2270        /// </param>
 2271        /// <param name="metadata">
 2272        /// Optional custom metadata to set for this blob.
 2273        /// </param>
 2274        /// <param name="tags">
 2275        /// Optional tags to set for this blob.
 2276        /// </param>
 2277        /// <param name="accessTier">
 2278        /// Optional <see cref="AccessTier"/>
 2279        /// Indicates the tier to be set on the blob.
 2280        /// </param>
 2281        /// <param name="sourceConditions">
 2282        /// Optional <see cref="BlobRequestConditions"/> to add
 2283        /// conditions on the copying of data from this source blob.
 2284        /// </param>
 2285        /// <param name="destinationConditions">
 2286        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
 2287        /// the copying of data to this blob.
 2288        /// </param>
 2289        /// <param name="async">
 2290        /// Whether to invoke the operation asynchronously.
 2291        /// </param>
 2292        /// <param name="cancellationToken">
 2293        /// Optional <see cref="CancellationToken"/> to propagate
 2294        /// notifications that the operation should be cancelled.
 2295        /// </param>
 2296        /// <returns>
 2297        /// A <see cref="Response{BlobCopyInfo}"/> describing the
 2298        /// state of the copy operation.
 2299        /// </returns>
 2300        /// <remarks>
 2301        /// A <see cref="RequestFailedException"/> will be thrown if
 2302        /// a failure occurs.
 2303        /// </remarks>
 2304        private async Task<Response<BlobCopyInfo>> SyncCopyFromUriInternal(
 2305            Uri source,
 2306            Metadata metadata,
 2307            Tags tags,
 2308            AccessTier? accessTier,
 2309            BlobRequestConditions sourceConditions,
 2310            BlobRequestConditions destinationConditions,
 2311            bool async,
 2312            CancellationToken cancellationToken)
 2313        {
 2314            using (Pipeline.BeginLoggingScope(nameof(BlobBaseClient)))
 2315            {
 2316                try
 2317                {
 2318                    Pipeline.LogMethodEnter(
 2319                    nameof(BlobBaseClient),
 2320                    message:
 2321                    $"{nameof(Uri)}: {Uri}\n" +
 2322                    $"{nameof(source)}: {source}\n" +
 2323                    $"{nameof(sourceConditions)}: {sourceConditions}\n" +
 2324                    $"{nameof(destinationConditions)}: {destinationConditions}");
 2325
 2326                    return await BlobRestClient.Blob.CopyFromUriAsync(
 2327                        clientDiagnostics: ClientDiagnostics,
 2328                        pipeline: Pipeline,
 2329                        resourceUri: Uri,
 2330                        copySource: source,
 2331                        version: Version.ToVersionString(),
 2332                        tier: accessTier,
 2333                        sourceIfModifiedSince: sourceConditions?.IfModifiedSince,
 2334                        sourceIfUnmodifiedSince: sourceConditions?.IfUnmodifiedSince,
 2335                        sourceIfMatch: sourceConditions?.IfMatch,
 2336                        sourceIfNoneMatch: sourceConditions?.IfNoneMatch,
 2337                        ifModifiedSince: destinationConditions?.IfModifiedSince,
 2338                        ifUnmodifiedSince: destinationConditions?.IfUnmodifiedSince,
 2339                        ifMatch: destinationConditions?.IfMatch,
 2340                        ifNoneMatch: destinationConditions?.IfNoneMatch,
 2341                        ifTags: destinationConditions?.TagConditions,
 2342                        leaseId: destinationConditions?.LeaseId,
 2343                        metadata: metadata,
 2344                        blobTagsString: tags?.ToTagsString(),
 2345                        async: async,
 2346                        operationName: $"{nameof(BlobBaseClient)}.{nameof(SyncCopyFromUri)}",
 2347                        cancellationToken: cancellationToken)
 2348                        .ConfigureAwait(false);
 2349                }
 2350                catch (Exception ex)
 2351                {
 2352                    Pipeline.LogException(ex);
 2353                    throw;
 2354                }
 2355                finally
 2356                {
 2357                    Pipeline.LogMethodExit(nameof(BlobBaseClient));
 2358                }
 2359            }
 2360        }
 2361        #endregion CopyFromUri
 2362
 2363        #region Delete
 2364        /// <summary>
 2365        /// The <see cref="Delete"/> operation marks the specified blob
 2366        /// or snapshot for  deletion. The blob is later deleted during
 2367        /// garbage collection.
 2368        ///
 2369        /// Note that in order to delete a blob, you must delete all of its
 2370        /// snapshots. You can delete both at the same time using
 2371        /// <see cref="DeleteSnapshotsOption.IncludeSnapshots"/>.
 2372        ///
 2373        /// For more information, see
 2374        /// <see href="https://docs.microsoft.com/rest/api/storageservices/delete-blob">
 2375        /// Delete Blob</see>.
 2376        /// </summary>
 2377        /// <param name="snapshotsOption">
 2378        /// Specifies options for deleting blob snapshots.
 2379        /// </param>
 2380        /// <param name="conditions">
 2381        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
 2382        /// deleting this blob.
 2383        /// </param>
 2384        /// <param name="cancellationToken">
 2385        /// Optional <see cref="CancellationToken"/> to propagate
 2386        /// notifications that the operation should be cancelled.
 2387        /// </param>
 2388        /// <returns>
 2389        /// A <see cref="Response"/> on successfully deleting.
 2390        /// </returns>
 2391        /// <remarks>
 2392        /// A <see cref="RequestFailedException"/> will be thrown if
 2393        /// a failure occurs.
 2394        /// </remarks>
 2395        public virtual Response Delete(
 2396            DeleteSnapshotsOption snapshotsOption = default,
 2397            BlobRequestConditions conditions = default,
 2398            CancellationToken cancellationToken = default) =>
 2399            DeleteInternal(
 2400                snapshotsOption,
 2401                conditions,
 2402                false, // async
 2403                cancellationToken)
 2404                .EnsureCompleted();
 2405
 2406        /// <summary>
 2407        /// The <see cref="DeleteAsync"/> operation marks the specified blob
 2408        /// or snapshot for  deletion. The blob is later deleted during
 2409        /// garbage collection.
 2410        ///
 2411        /// Note that in order to delete a blob, you must delete all of its
 2412        /// snapshots. You can delete both at the same time using
 2413        /// <see cref="DeleteSnapshotsOption.IncludeSnapshots"/>.
 2414        ///
 2415        /// For more information, see
 2416        /// <see href="https://docs.microsoft.com/rest/api/storageservices/delete-blob">
 2417        /// Delete Blob</see>.
 2418        /// </summary>
 2419        /// <param name="snapshotsOption">
 2420        /// Specifies options for deleting blob snapshots.
 2421        /// </param>
 2422        /// <param name="conditions">
 2423        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
 2424        /// deleting this blob.
 2425        /// </param>
 2426        /// <param name="cancellationToken">
 2427        /// Optional <see cref="CancellationToken"/> to propagate
 2428        /// notifications that the operation should be cancelled.
 2429        /// </param>
 2430        /// <returns>
 2431        /// A <see cref="Response"/> on successfully deleting.
 2432        /// </returns>
 2433        /// <remarks>
 2434        /// A <see cref="RequestFailedException"/> will be thrown if
 2435        /// a failure occurs.
 2436        /// </remarks>
 2437        public virtual async Task<Response> DeleteAsync(
 2438            DeleteSnapshotsOption snapshotsOption = default,
 2439            BlobRequestConditions conditions = default,
 2440            CancellationToken cancellationToken = default) =>
 2441            await DeleteInternal(
 2442                snapshotsOption,
 2443                conditions,
 2444                true, // async
 2445                cancellationToken)
 2446                .ConfigureAwait(false);
 2447
 2448        /// <summary>
 2449        /// The <see cref="DeleteIfExists"/> operation marks the specified blob
 2450        /// or snapshot for deletion, if the blob exists. The blob is later deleted
 2451        /// during garbage collection.
 2452        ///
 2453        /// Note that in order to delete a blob, you must delete all of its
 2454        /// snapshots. You can delete both at the same time using
 2455        /// <see cref="DeleteSnapshotsOption.IncludeSnapshots"/>.
 2456        ///
 2457        /// For more information, see
 2458        /// <see href="https://docs.microsoft.com/rest/api/storageservices/delete-blob">
 2459        /// Delete Blob</see>.
 2460        /// </summary>
 2461        /// <param name="snapshotsOption">
 2462        /// Specifies options for deleting blob snapshots.
 2463        /// </param>
 2464        /// <param name="conditions">
 2465        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
 2466        /// deleting this blob.
 2467        /// </param>
 2468        /// <param name="cancellationToken">
 2469        /// Optional <see cref="CancellationToken"/> to propagate
 2470        /// notifications that the operation should be cancelled.
 2471        /// </param>
 2472        /// <returns>
 2473        /// A <see cref="Response"/> on successfully deleting.
 2474        /// </returns>
 2475        /// <remarks>
 2476        /// A <see cref="RequestFailedException"/> will be thrown if
 2477        /// a failure occurs.
 2478        /// </remarks>
 2479        public virtual Response<bool> DeleteIfExists(
 2480            DeleteSnapshotsOption snapshotsOption = default,
 2481            BlobRequestConditions conditions = default,
 2482            CancellationToken cancellationToken = default) =>
 2483            DeleteIfExistsInternal(
 2484                snapshotsOption,
 2485                conditions ?? default,
 2486                false, // async
 2487                cancellationToken)
 2488                .EnsureCompleted();
 2489
 2490        /// <summary>
 2491        /// The <see cref="DeleteIfExistsAsync"/> operation marks the specified blob
 2492        /// or snapshot for deletion, if the blob exists. The blob is later deleted
 2493        /// during garbage collection.
 2494        ///
 2495        /// Note that in order to delete a blob, you must delete all of its
 2496        /// snapshots. You can delete both at the same time using
 2497        /// <see cref="DeleteSnapshotsOption.IncludeSnapshots"/>.
 2498        ///
 2499        /// For more information, see
 2500        /// <see href="https://docs.microsoft.com/rest/api/storageservices/delete-blob">
 2501        /// Delete Blob</see>.
 2502        /// </summary>
 2503        /// <param name="snapshotsOption">
 2504        /// Specifies options for deleting blob snapshots.
 2505        /// </param>
 2506        /// <param name="conditions">
 2507        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
 2508        /// deleting this blob.
 2509        /// </param>
 2510        /// <param name="cancellationToken">
 2511        /// Optional <see cref="CancellationToken"/> to propagate
 2512        /// notifications that the operation should be cancelled.
 2513        /// </param>
 2514        /// <returns>
 2515        /// A <see cref="Response"/> on successfully deleting.
 2516        /// </returns>
 2517        /// <remarks>
 2518        /// A <see cref="RequestFailedException"/> will be thrown if
 2519        /// a failure occurs.
 2520        /// </remarks>
 2521        public virtual async Task<Response<bool>> DeleteIfExistsAsync(
 2522            DeleteSnapshotsOption snapshotsOption = default,
 2523            BlobRequestConditions conditions = default,
 2524            CancellationToken cancellationToken = default) =>
 2525            await DeleteIfExistsInternal(
 2526                snapshotsOption,
 2527                conditions ?? default,
 2528                true, // async
 2529                cancellationToken)
 2530                .ConfigureAwait(false);
 2531
 2532        /// <summary>
 2533        /// The <see cref="DeleteIfExistsInternal"/> operation marks the specified blob
 2534        /// or snapshot for deletion, if the blob exists. The blob is later deleted
 2535        /// during garbage collection.
 2536        ///
 2537        /// Note that in order to delete a blob, you must delete all of its
 2538        /// snapshots. You can delete both at the same time using
 2539        /// <see cref="DeleteSnapshotsOption.IncludeSnapshots"/>.
 2540        ///
 2541        /// For more information, see
 2542        /// <see href="https://docs.microsoft.com/rest/api/storageservices/delete-blob">
 2543        /// Delete Blob</see>.
 2544        /// </summary>
 2545        /// <param name="snapshotsOption">
 2546        /// Specifies options for deleting blob snapshots.
 2547        /// </param>
 2548        /// <param name="conditions">
 2549        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
 2550        /// deleting this blob.
 2551        /// </param>
 2552        /// <param name="async">
 2553        /// Whether to invoke the operation asynchronously.
 2554        /// </param>
 2555        /// <param name="cancellationToken">
 2556        /// Optional <see cref="CancellationToken"/> to propagate
 2557        /// notifications that the operation should be cancelled.
 2558        /// </param>
 2559        /// <returns>
 2560        /// A <see cref="Response"/> on successfully deleting.
 2561        /// </returns>
 2562        /// <remarks>
 2563        /// A <see cref="RequestFailedException"/> will be thrown if
 2564        /// a failure occurs.
 2565        /// </remarks>
 2566        private async Task<Response<bool>> DeleteIfExistsInternal(
 2567            DeleteSnapshotsOption snapshotsOption,
 2568            BlobRequestConditions conditions,
 2569            bool async,
 2570            CancellationToken cancellationToken)
 2571        {
 2572            using (Pipeline.BeginLoggingScope(nameof(BlobBaseClient)))
 2573            {
 2574                Pipeline.LogMethodEnter(
 2575                    nameof(BlobBaseClient),
 2576                    message:
 2577                    $"{nameof(Uri)}: {Uri}\n" +
 2578                    $"{nameof(snapshotsOption)}: {snapshotsOption}\n" +
 2579                    $"{nameof(conditions)}: {conditions}");
 2580                try
 2581                {
 2582                    Response response = await DeleteInternal(
 2583                        snapshotsOption,
 2584                        conditions,
 2585                        async,
 2586                        cancellationToken,
 2587                        $"{nameof(BlobBaseClient)}.{nameof(DeleteIfExists)}")
 2588                        .ConfigureAwait(false);
 2589                    return Response.FromValue(true, response);
 2590                }
 2591                catch (RequestFailedException storageRequestFailedException)
 2592                when (storageRequestFailedException.ErrorCode == BlobErrorCode.BlobNotFound
 2593                    || storageRequestFailedException.ErrorCode == BlobErrorCode.ContainerNotFound)
 2594
 2595                {
 2596                    return Response.FromValue(false, default);
 2597                }
 2598                catch (Exception ex)
 2599                {
 2600                    Pipeline.LogException(ex);
 2601                    throw;
 2602                }
 2603                finally
 2604                {
 2605                    Pipeline.LogMethodExit(nameof(BlobBaseClient));
 2606                }
 2607            }
 2608        }
 2609
 2610        /// <summary>
 2611        /// The <see cref="DeleteInternal"/> operation marks the specified blob
 2612        /// or snapshot for  deletion. The blob is later deleted during
 2613        /// garbage collection.
 2614        ///
 2615        /// Note that in order to delete a blob, you must delete all of its
 2616        /// snapshots. You can delete both at the same time using
 2617        /// <see cref="DeleteSnapshotsOption.IncludeSnapshots"/>.
 2618        ///
 2619        /// For more information, see
 2620        /// <see href="https://docs.microsoft.com/rest/api/storageservices/delete-blob">
 2621        /// Delete Blob</see>.
 2622        /// </summary>
 2623        /// <param name="snapshotsOption">
 2624        /// Specifies options for deleting blob snapshots.
 2625        /// </param>
 2626        /// <param name="conditions">
 2627        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
 2628        /// deleting this blob.
 2629        /// </param>
 2630        /// <param name="async">
 2631        /// Whether to invoke the operation asynchronously.
 2632        /// </param>
 2633        /// <param name="cancellationToken">
 2634        /// Optional <see cref="CancellationToken"/> to propagate
 2635        /// notifications that the operation should be cancelled.
 2636        /// </param>
 2637        /// <param name="operationName">
 2638        /// Optional. To indicate if the name of the operation.
 2639        /// </param>
 2640        /// <returns>
 2641        /// A <see cref="Response"/> on successfully deleting.
 2642        /// </returns>
 2643        /// <remarks>
 2644        /// A <see cref="RequestFailedException"/> will be thrown if
 2645        /// a failure occurs.
 2646        /// </remarks>
 2647        private async Task<Response> DeleteInternal(
 2648            DeleteSnapshotsOption snapshotsOption,
 2649            BlobRequestConditions conditions,
 2650            bool async,
 2651            CancellationToken cancellationToken,
 2652            string operationName = null)
 2653        {
 2654            using (Pipeline.BeginLoggingScope(nameof(BlobBaseClient)))
 2655            {
 2656                Pipeline.LogMethodEnter(
 2657                    nameof(BlobBaseClient),
 2658                    message:
 2659                    $"{nameof(Uri)}: {Uri}\n" +
 2660                    $"{nameof(snapshotsOption)}: {snapshotsOption}\n" +
 2661                    $"{nameof(conditions)}: {conditions}");
 2662                try
 2663                {
 2664                    return await BlobRestClient.Blob.DeleteAsync(
 2665                        ClientDiagnostics,
 2666                        Pipeline,
 2667                        Uri,
 2668                        version: Version.ToVersionString(),
 2669                        deleteSnapshots: snapshotsOption == DeleteSnapshotsOption.None ? null : (DeleteSnapshotsOption?)
 2670                        leaseId: conditions?.LeaseId,
 2671                        ifModifiedSince: conditions?.IfModifiedSince,
 2672                        ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
 2673                        ifMatch: conditions?.IfMatch,
 2674                        ifNoneMatch: conditions?.IfNoneMatch,
 2675                        ifTags: conditions?.TagConditions,
 2676                        async: async,
 2677                        operationName: operationName ?? $"{nameof(BlobBaseClient)}.{nameof(Delete)}",
 2678                        cancellationToken: cancellationToken)
 2679                        .ConfigureAwait(false);
 2680                }
 2681                catch (Exception ex)
 2682                {
 2683                    Pipeline.LogException(ex);
 2684                    throw;
 2685                }
 2686                finally
 2687                {
 2688                    Pipeline.LogMethodExit(nameof(BlobBaseClient));
 2689                }
 2690            }
 2691        }
 2692        #endregion Delete
 2693
 2694        #region Exists
 2695        /// <summary>
 2696        /// The <see cref="Exists"/> operation can be called on a
 2697        /// <see cref="BlobBaseClient"/> to see if the associated blob
 2698        /// exists in the container on the storage account in the
 2699        /// storage service.
 2700        /// </summary>
 2701        /// <param name="cancellationToken">
 2702        /// Optional <see cref="CancellationToken"/> to propagate
 2703        /// notifications that the operation should be cancelled.
 2704        /// </param>
 2705        /// <returns>
 2706        /// Returns true if the blob exists.
 2707        /// </returns>
 2708        /// <remarks>
 2709        /// A <see cref="RequestFailedException"/> will be thrown if
 2710        /// a failure occurs.
 2711        /// </remarks>
 2712        public virtual Response<bool> Exists(
 2713            CancellationToken cancellationToken = default) =>
 2714            ExistsInternal(
 2715                async: false,
 2716                cancellationToken).EnsureCompleted();
 2717
 2718        /// <summary>
 2719        /// The <see cref="ExistsAsync"/> operation can be called on a
 2720        /// <see cref="BlobBaseClient"/> to see if the associated blob
 2721        /// exists in the container on the storage account in the storage service.
 2722        /// </summary>
 2723        /// <param name="cancellationToken">
 2724        /// Optional <see cref="CancellationToken"/> to propagate
 2725        /// notifications that the operation should be cancelled.
 2726        /// </param>
 2727        /// <returns>
 2728        /// Returns true if the blob exists.
 2729        /// </returns>
 2730        /// <remarks>
 2731        /// A <see cref="RequestFailedException"/> will be thrown if
 2732        /// a failure occurs.
 2733        /// </remarks>
 2734        public virtual async Task<Response<bool>> ExistsAsync(
 2735            CancellationToken cancellationToken = default) =>
 2736            await ExistsInternal(
 2737                async: true,
 2738                cancellationToken).ConfigureAwait(false);
 2739
 2740        /// <summary>
 2741        /// The <see cref="ExistsInternal"/> operation can be called on a
 2742        /// <see cref="BlobBaseClient"/> to see if the associated blob
 2743        /// exists on the storage account in the storage service.
 2744        /// </summary>
 2745        /// <param name="async">
 2746        /// Whether to invoke the operation asynchronously.
 2747        /// </param>
 2748        /// <param name="cancellationToken">
 2749        /// Optional <see cref="CancellationToken"/> to propagate
 2750        /// notifications that the operation should be cancelled.
 2751        /// </param>
 2752        /// <returns>
 2753        /// Returns true if the blob exists.
 2754        /// </returns>
 2755        /// <remarks>
 2756        /// A <see cref="RequestFailedException"/> will be thrown if
 2757        /// a failure occurs.
 2758        /// </remarks>
 2759        private async Task<Response<bool>> ExistsInternal(
 2760            bool async,
 2761            CancellationToken cancellationToken)
 2762        {
 2763            using (Pipeline.BeginLoggingScope(nameof(BlobBaseClient)))
 2764            {
 2765                Pipeline.LogMethodEnter(
 2766                    nameof(BlobBaseClient),
 2767                    message:
 2768                    $"{nameof(Uri)}: {Uri}");
 2769
 2770                try
 2771                {
 2772                    Response<BlobPropertiesInternal> response = await BlobRestClient.Blob.GetPropertiesAsync(
 2773                        ClientDiagnostics,
 2774                        Pipeline,
 2775                        Uri,
 2776                        version: Version.ToVersionString(),
 2777                        async: async,
 2778                        operationName: $"{nameof(BlobBaseClient)}.{nameof(Exists)}",
 2779                        cancellationToken: cancellationToken)
 2780                        .ConfigureAwait(false);
 2781
 2782                    return Response.FromValue(true, response.GetRawResponse());
 2783                }
 2784                catch (RequestFailedException storageRequestFailedException)
 2785                when (storageRequestFailedException.ErrorCode == BlobErrorCode.BlobNotFound
 2786                    || storageRequestFailedException.ErrorCode == BlobErrorCode.ContainerNotFound)
 2787                {
 2788                    return Response.FromValue(false, default);
 2789                }
 2790                catch (Exception ex)
 2791                {
 2792                    Pipeline.LogException(ex);
 2793                    throw;
 2794                }
 2795                finally
 2796                {
 2797                    Pipeline.LogMethodExit(nameof(BlobBaseClient));
 2798                }
 2799            }
 2800        }
 2801        #endregion Exists
 2802
 2803        #region Undelete
 2804        /// <summary>
 2805        /// The <see cref="Undelete"/> operation restores the contents
 2806        /// and metadata of a soft deleted blob and any associated soft
 2807        /// deleted snapshots.
 2808        ///
 2809        /// For more information, see
 2810        /// <see href="https://docs.microsoft.com/rest/api/storageservices/undelete-blob">
 2811        /// Undelete Blob</see>.
 2812        /// </summary>
 2813        /// <param name="cancellationToken">
 2814        /// Optional <see cref="CancellationToken"/> to propagate
 2815        /// notifications that the operation should be cancelled.
 2816        /// </param>
 2817        /// <returns>
 2818        /// A <see cref="Response"/> on successfully deleting.
 2819        /// </returns>
 2820        /// <remarks>
 2821        /// A <see cref="RequestFailedException"/> will be thrown if
 2822        /// a failure occurs.
 2823        /// </remarks>
 2824        public virtual Response Undelete(
 2825            CancellationToken cancellationToken = default) =>
 2826            UndeleteInternal(
 2827                false, // async
 2828                cancellationToken)
 2829                .EnsureCompleted();
 2830
 2831        /// <summary>
 2832        /// The <see cref="UndeleteAsync"/> operation restores the contents
 2833        /// and metadata of a soft deleted blob and any associated soft
 2834        /// deleted snapshots.
 2835        ///
 2836        /// For more information, see
 2837        /// <see href="https://docs.microsoft.com/rest/api/storageservices/undelete-blob">
 2838        /// Undelete Blob</see>.
 2839        /// </summary>
 2840        /// <param name="cancellationToken">
 2841        /// Optional <see cref="CancellationToken"/> to propagate
 2842        /// notifications that the operation should be cancelled.
 2843        /// </param>
 2844        /// <returns>
 2845        /// A <see cref="Response"/> on successfully deleting.
 2846        /// </returns>
 2847        /// <remarks>
 2848        /// A <see cref="RequestFailedException"/> will be thrown if
 2849        /// a failure occurs.
 2850        /// </remarks>
 2851        public virtual async Task<Response> UndeleteAsync(
 2852            CancellationToken cancellationToken = default) =>
 2853            await UndeleteInternal(
 2854                true, // async
 2855                cancellationToken)
 2856                .ConfigureAwait(false);
 2857
 2858        /// <summary>
 2859        /// The <see cref="UndeleteInternal"/> operation restores the contents
 2860        /// and metadata of a soft deleted blob and any associated soft
 2861        /// deleted snapshots.
 2862        ///
 2863        /// For more information, see
 2864        /// <see href="https://docs.microsoft.com/rest/api/storageservices/undelete-blob">
 2865        /// Undelete Blob</see>.
 2866        /// </summary>
 2867        /// <param name="async">
 2868        /// Whether to invoke the operation asynchronously.
 2869        /// </param>
 2870        /// <param name="cancellationToken">
 2871        /// Optional <see cref="CancellationToken"/> to propagate
 2872        /// notifications that the operation should be cancelled.
 2873        /// </param>
 2874        /// <returns>
 2875        /// A <see cref="Response"/> on successfully deleting.
 2876        /// </returns>
 2877        /// <remarks>
 2878        /// A <see cref="RequestFailedException"/> will be thrown if
 2879        /// a failure occurs.
 2880        /// </remarks>
 2881        private async Task<Response> UndeleteInternal(
 2882            bool async,
 2883            CancellationToken cancellationToken)
 2884        {
 2885            using (Pipeline.BeginLoggingScope(nameof(BlobBaseClient)))
 2886            {
 2887                Pipeline.LogMethodEnter(nameof(BlobBaseClient), message: $"{nameof(Uri)}: {Uri}");
 2888                try
 2889                {
 2890                    return await BlobRestClient.Blob.UndeleteAsync(
 2891                        ClientDiagnostics,
 2892                        Pipeline,
 2893                        Uri,
 2894                        version: Version.ToVersionString(),
 2895                        async: async,
 2896                        cancellationToken: cancellationToken,
 2897                        operationName: "BlobBaseClient.Undelete")
 2898                        .ConfigureAwait(false);
 2899                }
 2900                catch (Exception ex)
 2901                {
 2902                    Pipeline.LogException(ex);
 2903                    throw;
 2904                }
 2905                finally
 2906                {
 2907                    Pipeline.LogMethodExit(nameof(BlobBaseClient));
 2908                }
 2909            }
 2910        }
 2911        #endregion Undelete
 2912
 2913        #region GetProperties
 2914        /// <summary>
 2915        /// The <see cref="GetProperties"/> operation returns all
 2916        /// user-defined metadata, standard HTTP properties, and system
 2917        /// properties for the blob. It does not return the content of the
 2918        /// blob.
 2919        ///
 2920        /// For more information, see
 2921        /// <see href="https://docs.microsoft.com/rest/api/storageservices/get-blob-properties">
 2922        /// Get Blob Properties</see>.
 2923        /// </summary>
 2924        /// <param name="conditions">
 2925        /// Optional <see cref="BlobRequestConditions"/> to add
 2926        /// conditions on getting the blob's properties.
 2927        /// </param>
 2928        /// <param name="cancellationToken">
 2929        /// Optional <see cref="CancellationToken"/> to propagate
 2930        /// notifications that the operation should be cancelled.
 2931        /// </param>
 2932        /// <returns>
 2933        /// A <see cref="Response{BlobProperties}"/> describing the
 2934        /// blob's properties.
 2935        /// </returns>
 2936        /// <remarks>
 2937        /// A <see cref="RequestFailedException"/> will be thrown if
 2938        /// a failure occurs.
 2939        /// </remarks>
 2940        public virtual Response<BlobProperties> GetProperties(
 2941            BlobRequestConditions conditions = default,
 2942            CancellationToken cancellationToken = default) =>
 2943            GetPropertiesInternal(
 2944                conditions,
 2945                false, // async
 2946                cancellationToken)
 2947                .EnsureCompleted();
 2948
 2949        /// <summary>
 2950        /// The <see cref="GetPropertiesAsync"/> operation returns all
 2951        /// user-defined metadata, standard HTTP properties, and system
 2952        /// properties for the blob. It does not return the content of the
 2953        /// blob.
 2954        ///
 2955        /// For more information, see
 2956        /// <see href="https://docs.microsoft.com/rest/api/storageservices/get-blob-properties">
 2957        /// Get Blob Properties</see>.
 2958        /// </summary>
 2959        /// <param name="conditions">
 2960        /// Optional <see cref="BlobRequestConditions"/> to add
 2961        /// conditions on getting the blob's properties.
 2962        /// </param>
 2963        /// <param name="cancellationToken">
 2964        /// Optional <see cref="CancellationToken"/> to propagate
 2965        /// notifications that the operation should be cancelled.
 2966        /// </param>
 2967        /// <returns>
 2968        /// A <see cref="Response{BlobProperties}"/> describing the
 2969        /// blob's properties.
 2970        /// </returns>
 2971        /// <remarks>
 2972        /// A <see cref="RequestFailedException"/> will be thrown if
 2973        /// a failure occurs.
 2974        /// </remarks>
 2975        public virtual async Task<Response<BlobProperties>> GetPropertiesAsync(
 2976            BlobRequestConditions conditions = default,
 2977            CancellationToken cancellationToken = default) =>
 2978            await GetPropertiesInternal(
 2979                conditions,
 2980                true, // async
 2981                cancellationToken)
 2982                .ConfigureAwait(false);
 2983
 2984        /// <summary>
 2985        /// The <see cref="GetPropertiesInternal"/> operation returns all
 2986        /// user-defined metadata, standard HTTP properties, and system
 2987        /// properties for the blob. It does not return the content of the
 2988        /// blob.
 2989        ///
 2990        /// For more information, see
 2991        /// <see href="https://docs.microsoft.com/rest/api/storageservices/get-blob-properties">
 2992        /// Get Blob Properties</see>.
 2993        /// </summary>
 2994        /// <param name="conditions">
 2995        /// Optional <see cref="BlobRequestConditions"/> to add
 2996        /// conditions on getting the blob's properties.
 2997        /// </param>
 2998        /// <param name="async">
 2999        /// Whether to invoke the operation asynchronously.
 3000        /// </param>
 3001        /// <param name="cancellationToken">
 3002        /// Optional <see cref="CancellationToken"/> to propagate
 3003        /// notifications that the operation should be cancelled.
 3004        /// </param>
 3005        /// <returns>
 3006        /// A <see cref="Response{BlobProperties}"/> describing the
 3007        /// blob's properties.
 3008        /// </returns>
 3009        /// <remarks>
 3010        /// A <see cref="RequestFailedException"/> will be thrown if
 3011        /// a failure occurs.
 3012        /// </remarks>
 3013        private async Task<Response<BlobProperties>> GetPropertiesInternal(
 3014            BlobRequestConditions conditions,
 3015            bool async,
 3016            CancellationToken cancellationToken)
 3017        {
 3018            using (Pipeline.BeginLoggingScope(nameof(BlobBaseClient)))
 3019            {
 3020                Pipeline.LogMethodEnter(
 3021                    nameof(BlobBaseClient),
 3022                    message:
 3023                    $"{nameof(Uri)}: {Uri}\n" +
 3024                    $"{nameof(conditions)}: {conditions}");
 3025                try
 3026                {
 3027                    Response<BlobPropertiesInternal> response = await BlobRestClient.Blob.GetPropertiesAsync(
 3028                        ClientDiagnostics,
 3029                        Pipeline,
 3030                        Uri,
 3031                        version: Version.ToVersionString(),
 3032                        leaseId: conditions?.LeaseId,
 3033                        encryptionKey: CustomerProvidedKey?.EncryptionKey,
 3034                        encryptionKeySha256: CustomerProvidedKey?.EncryptionKeyHash,
 3035                        encryptionAlgorithm: CustomerProvidedKey?.EncryptionAlgorithm,
 3036                        ifModifiedSince: conditions?.IfModifiedSince,
 3037                        ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
 3038                        ifMatch: conditions?.IfMatch,
 3039                        ifNoneMatch: conditions?.IfNoneMatch,
 3040                        ifTags: conditions?.TagConditions,
 3041                        async: async,
 3042                        operationName: "BlobBaseClient.GetProperties",
 3043                        cancellationToken: cancellationToken)
 3044                        .ConfigureAwait(false);
 3045
 3046                    return Response.FromValue(
 3047                        response.Value.ToBlobProperties(),
 3048                        response.GetRawResponse());
 3049                }
 3050                catch (Exception ex)
 3051                {
 3052                    Pipeline.LogException(ex);
 3053                    throw;
 3054                }
 3055                finally
 3056                {
 3057                    Pipeline.LogMethodExit(nameof(BlobBaseClient));
 3058                }
 3059            }
 3060        }
 3061        #endregion GetProperties
 3062
 3063        #region SetHttpHeaders
 3064        /// <summary>
 3065        /// The <see cref="SetHttpHeaders"/> operation sets system
 3066        /// properties on the blob.
 3067        ///
 3068        /// For more information, see
 3069        /// <see href="https://docs.microsoft.com/rest/api/storageservices/set-blob-properties">
 3070        /// Set Blob Properties</see>.
 3071        /// </summary>
 3072        /// <param name="httpHeaders">
 3073        /// Optional. The standard HTTP header system properties to set.
 3074        /// If not specified, existing values will be cleared.
 3075        /// </param>
 3076        /// <param name="conditions">
 3077        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
 3078        /// setting the blob's HTTP headers.
 3079        /// </param>
 3080        /// <param name="cancellationToken">
 3081        /// Optional <see cref="CancellationToken"/> to propagate
 3082        /// notifications that the operation should be cancelled.
 3083        /// </param>
 3084        /// <returns>
 3085        /// A <see cref="Response{BlobInfo}"/> describing the updated
 3086        /// blob.
 3087        /// </returns>
 3088        /// <remarks>
 3089        /// A <see cref="RequestFailedException"/> will be thrown if
 3090        /// a failure occurs.
 3091        /// </remarks>
 3092        public virtual Response<BlobInfo> SetHttpHeaders(
 3093            BlobHttpHeaders httpHeaders = default,
 3094            BlobRequestConditions conditions = default,
 3095            CancellationToken cancellationToken = default) =>
 3096            SetHttpHeadersInternal(
 3097                httpHeaders,
 3098                conditions,
 3099                false, // async
 3100                cancellationToken)
 3101                .EnsureCompleted();
 3102
 3103        /// <summary>
 3104        /// The <see cref="SetHttpHeadersAsync"/> operation sets system
 3105        /// properties on the blob.
 3106        ///
 3107        /// For more information, see
 3108        /// <see href="https://docs.microsoft.com/rest/api/storageservices/set-blob-properties">
 3109        /// Set Blob Properties</see>.
 3110        /// </summary>
 3111        /// <param name="httpHeaders">
 3112        /// Optional. The standard HTTP header system properties to set.  If not specified, existing values will be clea
 3113        /// </param>
 3114        /// <param name="conditions">
 3115        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
 3116        /// setting the blob's HTTP headers.
 3117        /// </param>
 3118        /// <param name="cancellationToken">
 3119        /// Optional <see cref="CancellationToken"/> to propagate
 3120        /// notifications that the operation should be cancelled.
 3121        /// </param>
 3122        /// <returns>
 3123        /// A <see cref="Response{BlobInfo}"/> describing the updated
 3124        /// blob.
 3125        /// </returns>
 3126        /// <remarks>
 3127        /// A <see cref="RequestFailedException"/> will be thrown if
 3128        /// a failure occurs.
 3129        /// </remarks>
 3130        public virtual async Task<Response<BlobInfo>> SetHttpHeadersAsync(
 3131            BlobHttpHeaders httpHeaders = default,
 3132            BlobRequestConditions conditions = default,
 3133            CancellationToken cancellationToken = default) =>
 3134            await SetHttpHeadersInternal(
 3135                httpHeaders,
 3136                conditions,
 3137                true, // async
 3138                cancellationToken)
 3139                .ConfigureAwait(false);
 3140
 3141        /// <summary>
 3142        /// The <see cref="SetHttpHeadersInternal"/> operation sets system
 3143        /// properties on the blob.
 3144        ///
 3145        /// For more information, see
 3146        /// <see href="https://docs.microsoft.com/rest/api/storageservices/set-blob-properties">
 3147        /// Set Blob Properties</see>.
 3148        /// </summary>
 3149        /// <param name="httpHeaders">
 3150        /// Optional. The standard HTTP header system properties to set.  If not specified, existing values will be clea
 3151        /// </param>
 3152        /// <param name="conditions">
 3153        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
 3154        /// setting the blob's HTTP headers.
 3155        /// </param>
 3156        /// <param name="async">
 3157        /// Whether to invoke the operation asynchronously.
 3158        /// </param>
 3159        /// <param name="cancellationToken">
 3160        /// Optional <see cref="CancellationToken"/> to propagate
 3161        /// notifications that the operation should be cancelled.
 3162        /// </param>
 3163        /// <returns>
 3164        /// A <see cref="Response{BlobInfo}"/> describing the updated
 3165        /// blob.
 3166        /// </returns>
 3167        /// <remarks>
 3168        /// A <see cref="RequestFailedException"/> will be thrown if
 3169        /// a failure occurs.
 3170        /// </remarks>
 3171        private async Task<Response<BlobInfo>> SetHttpHeadersInternal(
 3172            BlobHttpHeaders httpHeaders,
 3173            BlobRequestConditions conditions,
 3174            bool async,
 3175            CancellationToken cancellationToken)
 3176        {
 3177            using (Pipeline.BeginLoggingScope(nameof(BlobBaseClient)))
 3178            {
 3179                Pipeline.LogMethodEnter(
 3180                    nameof(BlobBaseClient),
 3181                    message:
 3182                    $"{nameof(Uri)}: {Uri}\n" +
 3183                    $"{nameof(httpHeaders)}: {httpHeaders}\n" +
 3184                    $"{nameof(conditions)}: {conditions}");
 3185                try
 3186                {
 3187                    Response<SetHttpHeadersOperation> response =
 3188                        await BlobRestClient.Blob.SetHttpHeadersAsync(
 3189                            ClientDiagnostics,
 3190                            Pipeline,
 3191                            Uri,
 3192                            version: Version.ToVersionString(),
 3193                            blobCacheControl: httpHeaders?.CacheControl,
 3194                            blobContentType: httpHeaders?.ContentType,
 3195                            blobContentHash: httpHeaders?.ContentHash,
 3196                            blobContentEncoding: httpHeaders?.ContentEncoding,
 3197                            blobContentLanguage: httpHeaders?.ContentLanguage,
 3198                            blobContentDisposition: httpHeaders?.ContentDisposition,
 3199                            leaseId: conditions?.LeaseId,
 3200                            ifModifiedSince: conditions?.IfModifiedSince,
 3201                            ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
 3202                            ifMatch: conditions?.IfMatch,
 3203                            ifNoneMatch: conditions?.IfNoneMatch,
 3204                            ifTags: conditions?.TagConditions,
 3205                            async: async,
 3206                            operationName: "BlobBaseClient.SetHttpHeaders",
 3207                            cancellationToken: cancellationToken)
 3208                            .ConfigureAwait(false);
 3209                    return Response.FromValue(
 3210                        new BlobInfo
 3211                        {
 3212                            LastModified = response.Value.LastModified,
 3213                            ETag = response.Value.ETag,
 3214                            BlobSequenceNumber = response.Value.BlobSequenceNumber
 3215                        }, response.GetRawResponse());
 3216                }
 3217                catch (Exception ex)
 3218                {
 3219                    Pipeline.LogException(ex);
 3220                    throw;
 3221                }
 3222                finally
 3223                {
 3224                    Pipeline.LogMethodExit(nameof(BlobBaseClient));
 3225                }
 3226            }
 3227        }
 3228        #endregion SetHttpHeaders
 3229
 3230        #region SetMetadata
 3231        /// <summary>
 3232        /// The <see cref="SetMetadata"/> operation sets user-defined
 3233        /// metadata for the specified blob as one or more name-value pairs.
 3234        ///
 3235        /// For more information, see
 3236        /// <see href="https://docs.microsoft.com/rest/api/storageservices/set-blob-metadata">
 3237        /// Set Blob Metadata</see>.
 3238        /// </summary>
 3239        /// <param name="metadata">
 3240        /// Custom metadata to set for this blob.
 3241        /// </param>
 3242        /// <param name="conditions">
 3243        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
 3244        /// setting the blob's metadata.
 3245        /// </param>
 3246        /// <param name="cancellationToken">
 3247        /// Optional <see cref="CancellationToken"/> to propagate
 3248        /// notifications that the operation should be cancelled.
 3249        /// </param>
 3250        /// <returns>
 3251        /// A <see cref="Response{BlobInfo}"/> describing the updated
 3252        /// blob.
 3253        /// </returns>
 3254        /// <remarks>
 3255        /// A <see cref="RequestFailedException"/> will be thrown if
 3256        /// a failure occurs.
 3257        /// </remarks>
 3258        public virtual Response<BlobInfo> SetMetadata(
 3259            Metadata metadata,
 3260            BlobRequestConditions conditions = default,
 3261            CancellationToken cancellationToken = default) =>
 3262            SetMetadataInternal(
 3263                metadata,
 3264                conditions,
 3265                false, // async
 3266                cancellationToken)
 3267                .EnsureCompleted();
 3268
 3269        /// <summary>
 3270        /// The <see cref="SetMetadataAsync"/> operation sets user-defined
 3271        /// metadata for the specified blob as one or more name-value pairs.
 3272        ///
 3273        /// For more information, see
 3274        /// <see href="https://docs.microsoft.com/rest/api/storageservices/set-blob-metadata">
 3275        /// Set Blob Metadata</see>.
 3276        /// </summary>
 3277        /// <param name="metadata">
 3278        /// Custom metadata to set for this blob.
 3279        /// </param>
 3280        /// <param name="conditions">
 3281        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
 3282        /// setting the blob's metadata.
 3283        /// </param>
 3284        /// <param name="cancellationToken">
 3285        /// Optional <see cref="CancellationToken"/> to propagate
 3286        /// notifications that the operation should be cancelled.
 3287        /// </param>
 3288        /// <returns>
 3289        /// A <see cref="Response{BlobInfo}"/> describing the updated
 3290        /// blob.
 3291        /// </returns>
 3292        /// <remarks>
 3293        /// A <see cref="RequestFailedException"/> will be thrown if
 3294        /// a failure occurs.
 3295        /// </remarks>
 3296        public virtual async Task<Response<BlobInfo>> SetMetadataAsync(
 3297            Metadata metadata,
 3298            BlobRequestConditions conditions = default,
 3299            CancellationToken cancellationToken = default) =>
 3300            await SetMetadataInternal(
 3301                metadata,
 3302                conditions,
 3303                true, // async
 3304                cancellationToken)
 3305                .ConfigureAwait(false);
 3306
 3307        /// <summary>
 3308        /// The <see cref="SetMetadataInternal"/> operation sets user-defined
 3309        /// metadata for the specified blob as one or more name-value pairs.
 3310        ///
 3311        /// For more information, see
 3312        /// <see href="https://docs.microsoft.com/rest/api/storageservices/set-blob-metadata">
 3313        /// Set Blob Metadata</see>.
 3314        /// </summary>
 3315        /// <param name="metadata">
 3316        /// Custom metadata to set for this blob.
 3317        /// </param>
 3318        /// <param name="conditions">
 3319        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
 3320        /// setting the blob's metadata.
 3321        /// </param>
 3322        /// <param name="async">
 3323        /// Whether to invoke the operation asynchronously.
 3324        /// </param>
 3325        /// <param name="cancellationToken">
 3326        /// Optional <see cref="CancellationToken"/> to propagate
 3327        /// notifications that the operation should be cancelled.
 3328        /// </param>
 3329        /// <returns>
 3330        /// A <see cref="Response{BlobInfo}"/> describing the updated
 3331        /// blob.
 3332        /// </returns>
 3333        /// <remarks>
 3334        /// A <see cref="RequestFailedException"/> will be thrown if
 3335        /// a failure occurs.
 3336        /// </remarks>
 3337        private async Task<Response<BlobInfo>> SetMetadataInternal(
 3338            Metadata metadata,
 3339            BlobRequestConditions conditions,
 3340            bool async,
 3341            CancellationToken cancellationToken)
 3342        {
 3343            using (Pipeline.BeginLoggingScope(nameof(BlobBaseClient)))
 3344            {
 3345                Pipeline.LogMethodEnter(
 3346                    nameof(BlobBaseClient),
 3347                    message:
 3348                    $"{nameof(Uri)}: {Uri}\n" +
 3349                    $"{nameof(conditions)}: {conditions}");
 3350                try
 3351                {
 3352                    Response<SetMetadataOperation> response =
 3353                        await BlobRestClient.Blob.SetMetadataAsync(
 3354                            ClientDiagnostics,
 3355                            Pipeline,
 3356                            Uri,
 3357                            version: Version.ToVersionString(),
 3358                            metadata: metadata,
 3359                            leaseId: conditions?.LeaseId,
 3360                            encryptionKey: CustomerProvidedKey?.EncryptionKey,
 3361                            encryptionKeySha256: CustomerProvidedKey?.EncryptionKeyHash,
 3362                            encryptionAlgorithm: CustomerProvidedKey?.EncryptionAlgorithm,
 3363                            encryptionScope: EncryptionScope,
 3364                            ifModifiedSince: conditions?.IfModifiedSince,
 3365                            ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
 3366                            ifMatch: conditions?.IfMatch,
 3367                            ifNoneMatch: conditions?.IfNoneMatch,
 3368                            ifTags: conditions?.TagConditions,
 3369                            async: async,
 3370                            operationName: "BlobBaseClient.SetMetadata",
 3371                            cancellationToken: cancellationToken)
 3372                            .ConfigureAwait(false);
 3373                    return Response.FromValue(
 3374                        new BlobInfo
 3375                        {
 3376                            LastModified = response.Value.LastModified,
 3377                            ETag = response.Value.ETag,
 3378                            VersionId = response.Value.VersionId
 3379                        }, response.GetRawResponse());
 3380                }
 3381                catch (Exception ex)
 3382                {
 3383                    Pipeline.LogException(ex);
 3384                    throw;
 3385                }
 3386                finally
 3387                {
 3388                    Pipeline.LogMethodExit(nameof(BlobBaseClient));
 3389                }
 3390            }
 3391        }
 3392        #endregion SetMetadata
 3393
 3394        #region CreateSnapshot
 3395        /// <summary>
 3396        /// The <see cref="CreateSnapshot"/> operation creates a
 3397        /// read-only snapshot of a blob.
 3398        ///
 3399        /// For more information, see
 3400        /// <see href="https://docs.microsoft.com/rest/api/storageservices/snapshot-blob">
 3401        /// Snapshot Blob</see>.
 3402        /// </summary>
 3403        /// <param name="metadata">
 3404        /// Optional custom metadata to set for this blob snapshot.
 3405        /// </param>
 3406        /// <param name="conditions">
 3407        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
 3408        /// setting creating this snapshot.
 3409        /// </param>
 3410        /// <param name="cancellationToken">
 3411        /// Optional <see cref="CancellationToken"/> to propagate
 3412        /// notifications that the operation should be cancelled.
 3413        /// </param>
 3414        /// <returns>
 3415        /// A <see cref="Response{BlobSnapshotInfo}"/> describing the
 3416        /// new blob snapshot.
 3417        /// </returns>
 3418        /// <remarks>
 3419        /// A <see cref="RequestFailedException"/> will be thrown if
 3420        /// a failure occurs.
 3421        /// </remarks>
 3422        public virtual Response<BlobSnapshotInfo> CreateSnapshot(
 3423            Metadata metadata = default,
 3424            BlobRequestConditions conditions = default,
 3425            CancellationToken cancellationToken = default) =>
 3426            CreateSnapshotInternal(
 3427                metadata,
 3428                conditions,
 3429                false, // async
 3430                cancellationToken)
 3431                .EnsureCompleted();
 3432
 3433        /// <summary>
 3434        /// The <see cref="CreateSnapshotAsync"/> operation creates a
 3435        /// read-only snapshot of a blob.
 3436        ///
 3437        /// For more information, see
 3438        /// <see href="https://docs.microsoft.com/rest/api/storageservices/snapshot-blob">
 3439        /// Snapshot Blob</see>.
 3440        /// </summary>
 3441        /// <param name="metadata">
 3442        /// Optional custom metadata to set for this blob snapshot.
 3443        /// </param>
 3444        /// <param name="conditions">
 3445        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
 3446        /// setting creating this snapshot.
 3447        /// </param>
 3448        /// <param name="cancellationToken">
 3449        /// Optional <see cref="CancellationToken"/> to propagate
 3450        /// notifications that the operation should be cancelled.
 3451        /// </param>
 3452        /// <returns>
 3453        /// A <see cref="Response{BlobSnapshotInfo}"/> describing the
 3454        /// new blob snapshot.
 3455        /// </returns>
 3456        /// <remarks>
 3457        /// A <see cref="RequestFailedException"/> will be thrown if
 3458        /// a failure occurs.
 3459        /// </remarks>
 3460        public virtual async Task<Response<BlobSnapshotInfo>> CreateSnapshotAsync(
 3461            Metadata metadata = default,
 3462            BlobRequestConditions conditions = default,
 3463            CancellationToken cancellationToken = default) =>
 3464            await CreateSnapshotInternal(
 3465                metadata,
 3466                conditions,
 3467                true, // async
 3468                cancellationToken)
 3469                .ConfigureAwait(false);
 3470
 3471        /// <summary>
 3472        /// The <see cref="CreateSnapshotInternal"/> operation creates a
 3473        /// read-only snapshot of a blob.
 3474        ///
 3475        /// For more information, see
 3476        /// <see href="https://docs.microsoft.com/rest/api/storageservices/snapshot-blob">
 3477        /// Snapshot Blob</see>.
 3478        /// </summary>
 3479        /// <param name="metadata">
 3480        /// Optional custom metadata to set for this blob snapshot.
 3481        /// </param>
 3482        /// <param name="conditions">
 3483        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
 3484        /// setting creating this snapshot.
 3485        /// </param>
 3486        /// <param name="async">
 3487        /// Whether to invoke the operation asynchronously.
 3488        /// </param>
 3489        /// <param name="cancellationToken">
 3490        /// Optional <see cref="CancellationToken"/> to propagate
 3491        /// notifications that the operation should be cancelled.
 3492        /// </param>
 3493        /// <returns>
 3494        /// A <see cref="Response{BlobSnapshotInfo}"/> describing the
 3495        /// new blob snapshot.
 3496        /// </returns>
 3497        /// <remarks>
 3498        /// A <see cref="RequestFailedException"/> will be thrown if
 3499        /// a failure occurs.
 3500        /// </remarks>
 3501        private async Task<Response<BlobSnapshotInfo>> CreateSnapshotInternal(
 3502            Metadata metadata,
 3503            BlobRequestConditions conditions,
 3504            bool async,
 3505            CancellationToken cancellationToken)
 3506        {
 3507            using (Pipeline.BeginLoggingScope(nameof(BlobBaseClient)))
 3508            {
 3509                Pipeline.LogMethodEnter(
 3510                    nameof(BlobBaseClient),
 3511                    message:
 3512                    $"{nameof(Uri)}: {Uri}\n" +
 3513                    $"{nameof(conditions)}: {conditions}");
 3514                try
 3515                {
 3516                    return await BlobRestClient.Blob.CreateSnapshotAsync(
 3517                        ClientDiagnostics,
 3518                        Pipeline,
 3519                        Uri,
 3520                        version: Version.ToVersionString(),
 3521                        metadata: metadata,
 3522                        encryptionKey: CustomerProvidedKey?.EncryptionKey,
 3523                        encryptionKeySha256: CustomerProvidedKey?.EncryptionKeyHash,
 3524                        encryptionAlgorithm: CustomerProvidedKey?.EncryptionAlgorithm,
 3525                        encryptionScope: EncryptionScope,
 3526                        ifModifiedSince: conditions?.IfModifiedSince,
 3527                        ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
 3528                        ifMatch: conditions?.IfMatch,
 3529                        ifNoneMatch: conditions?.IfNoneMatch,
 3530                        leaseId: conditions?.LeaseId,
 3531                        ifTags: conditions?.TagConditions,
 3532                        async: async,
 3533                        operationName: "BlobBaseClient.CreateSnapshot",
 3534                        cancellationToken: cancellationToken)
 3535                        .ConfigureAwait(false);
 3536                }
 3537                catch (Exception ex)
 3538                {
 3539                    Pipeline.LogException(ex);
 3540                    throw;
 3541                }
 3542                finally
 3543                {
 3544                    Pipeline.LogMethodExit(nameof(BlobBaseClient));
 3545                }
 3546            }
 3547        }
 3548        #endregion CreateSnapshot
 3549
 3550        #region SetAccessTier
 3551        /// <summary>
 3552        /// The <see cref="SetAccessTier"/> operation sets the tier on a blob.
 3553        /// The operation is allowed on a page blob in a premium storage
 3554        /// account and on a block blob in a blob storage or general purpose
 3555        /// v2 account.
 3556        ///
 3557        /// A premium page blob's tier determines the allowed size, IOPS, and
 3558        /// bandwidth of the blob.  A block blob's tier determines
 3559        /// Hot/Cool/Archive storage type.  This operation does not update the
 3560        /// blob's ETag.  For detailed information about block blob level
 3561        /// tiering <see href="https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blob-storage-tiers">
 3562        /// Blob Storage Tiers</see>.
 3563        ///
 3564        /// For more information about setting the tier, see
 3565        /// <see href="https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blob-storage-tiers">
 3566        /// Blob Storage Tiers</see>.
 3567        /// </summary>
 3568        /// <param name="accessTier">
 3569        /// Indicates the tier to be set on the blob.
 3570        /// </param>
 3571        /// <param name="conditions">
 3572        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
 3573        /// setting the access tier.
 3574        /// </param>
 3575        /// <param name="rehydratePriority">
 3576        /// Optional <see cref="RehydratePriority"/>
 3577        /// Indicates the priority with which to rehydrate an archived blob.
 3578        /// </param>
 3579        /// <param name="cancellationToken">
 3580        /// Optional <see cref="CancellationToken"/> to propagate
 3581        /// notifications that the operation should be cancelled.
 3582        /// </param>
 3583        /// <returns>
 3584        /// A <see cref="Response"/> on successfully setting the tier.
 3585        /// </returns>
 3586        /// <remarks>
 3587        /// A <see cref="RequestFailedException"/> will be thrown if
 3588        /// a failure occurs.
 3589        /// </remarks>
 3590        public virtual Response SetAccessTier(
 3591            AccessTier accessTier,
 3592            BlobRequestConditions conditions = default,
 3593            RehydratePriority? rehydratePriority = default,
 3594            CancellationToken cancellationToken = default) =>
 3595            SetAccessTierInternal(
 3596                accessTier,
 3597                conditions,
 3598                rehydratePriority,
 3599                false, // async
 3600                cancellationToken)
 3601                .EnsureCompleted();
 3602
 3603        /// <summary>
 3604        /// The <see cref="SetAccessTierAsync"/> operation sets the tier on a blob.
 3605        /// The operation is allowed on a page blob in a premium storage
 3606        /// account and on a block blob in a blob storage or general purpose
 3607        /// v2 account.
 3608        ///
 3609        /// A premium page blob's tier determines the allowed size, IOPS, and
 3610        /// bandwidth of the blob.  A block blob's tier determines
 3611        /// Hot/Cool/Archive storage type.  This operation does not update the
 3612        /// blob's ETag.  For detailed information about block blob level
 3613        /// tiering <see href="https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blob-storage-tiers">
 3614        /// Blob Storage Tiers</see>.
 3615        ///
 3616        /// For more information about setting the tier, see
 3617        /// <see href="https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blob-storage-tiers">
 3618        /// Blob Storage Tiers</see>.
 3619        /// </summary>
 3620        /// <param name="accessTier">
 3621        /// Indicates the tier to be set on the blob.
 3622        /// </param>
 3623        /// <param name="conditions">
 3624        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
 3625        /// setting the access tier.
 3626        /// </param>
 3627        /// <param name="rehydratePriority">
 3628        /// Optional <see cref="RehydratePriority"/>
 3629        /// Indicates the priority with which to rehydrate an archived blob.
 3630        /// </param>
 3631        /// <param name="cancellationToken">
 3632        /// Optional <see cref="CancellationToken"/> to propagate
 3633        /// notifications that the operation should be cancelled.
 3634        /// </param>
 3635        /// <returns>
 3636        /// A <see cref="Response"/> on successfully setting the tier.
 3637        /// </returns>
 3638        /// <remarks>
 3639        /// A <see cref="RequestFailedException"/> will be thrown if
 3640        /// a failure occurs.
 3641        /// </remarks>
 3642        public virtual async Task<Response> SetAccessTierAsync(
 3643            AccessTier accessTier,
 3644            BlobRequestConditions conditions = default,
 3645            RehydratePriority? rehydratePriority = default,
 3646            CancellationToken cancellationToken = default) =>
 3647            await SetAccessTierInternal(
 3648                accessTier,
 3649                conditions,
 3650                rehydratePriority,
 3651                true, // async
 3652                cancellationToken)
 3653                .ConfigureAwait(false);
 3654
 3655        /// <summary>
 3656        /// The <see cref="SetAccessTierInternal"/> operation sets the tier on a blob.
 3657        /// The operation is allowed on a page blob in a premium storage
 3658        /// account and on a block blob in a blob storage or general purpose
 3659        /// v2 account.
 3660        ///
 3661        /// A premium page blob's tier determines the allowed size, IOPS, and
 3662        /// bandwidth of the blob.  A block blob's tier determines
 3663        /// Hot/Cool/Archive storage type.  This operation does not update the
 3664        /// blob's ETag.  For detailed information about block blob level
 3665        /// tiering <see href="https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blob-storage-tiers">
 3666        /// Blob Storage Tiers</see>.
 3667        ///
 3668        /// For more information about setting the tier, see
 3669        /// <see href="https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blob-storage-tiers">
 3670        /// Blob Storage Tiers</see>.
 3671        /// </summary>
 3672        /// <param name="accessTier">
 3673        /// Indicates the tier to be set on the blob.
 3674        /// </param>
 3675        /// <param name="conditions">
 3676        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
 3677        /// setting the access tier.
 3678        /// </param>
 3679        /// <param name="rehydratePriority">
 3680        /// Optional <see cref="RehydratePriority"/>
 3681        /// Indicates the priority with which to rehydrate an archived blob.
 3682        /// </param>
 3683        /// <param name="async">
 3684        /// Whether to invoke the operation asynchronously.
 3685        /// </param>
 3686        /// <param name="cancellationToken">
 3687        /// Optional <see cref="CancellationToken"/> to propagate
 3688        /// notifications that the operation should be cancelled.
 3689        /// </param>
 3690        /// <returns>
 3691        /// A <see cref="Response"/> on successfully setting the tier.
 3692        /// </returns>
 3693        /// <remarks>
 3694        /// A <see cref="RequestFailedException"/> will be thrown if
 3695        /// a failure occurs.
 3696        /// </remarks>
 3697        private async Task<Response> SetAccessTierInternal(
 3698            AccessTier accessTier,
 3699            BlobRequestConditions conditions,
 3700            RehydratePriority? rehydratePriority,
 3701            bool async,
 3702            CancellationToken cancellationToken)
 3703        {
 3704            using (Pipeline.BeginLoggingScope(nameof(BlobBaseClient)))
 3705            {
 3706                Pipeline.LogMethodEnter(
 3707                    nameof(BlobBaseClient),
 3708                    message:
 3709                    $"{nameof(Uri)}: {Uri}\n" +
 3710                    $"{nameof(accessTier)}: {accessTier}\n" +
 3711                    $"{nameof(conditions)}: {conditions}");
 3712                try
 3713                {
 3714                    return await BlobRestClient.Blob.SetAccessTierAsync(
 3715                        ClientDiagnostics,
 3716                        Pipeline,
 3717                        Uri,
 3718                        tier: accessTier,
 3719                        version: Version.ToVersionString(),
 3720                        rehydratePriority: rehydratePriority,
 3721                        leaseId: conditions?.LeaseId,
 3722                        ifTags: conditions?.TagConditions,
 3723                        async: async,
 3724                        operationName: "BlobBaseClient.SetAccessTier",
 3725                        cancellationToken: cancellationToken)
 3726                        .ConfigureAwait(false);
 3727                }
 3728                catch (Exception ex)
 3729                {
 3730                    Pipeline.LogException(ex);
 3731                    throw;
 3732                }
 3733                finally
 3734                {
 3735                    Pipeline.LogMethodExit(nameof(BlobBaseClient));
 3736                }
 3737            }
 3738        }
 3739        #endregion SetAccessTier
 3740
 3741        #region GetTags
 3742        /// <summary>
 3743        /// Gets the tags associated with the underlying blob.
 3744        ///
 3745        /// For more information, see
 3746        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/get-blob-tags">
 3747        /// Get Blob Tags</see>
 3748        /// </summary>
 3749        /// <param name="conditions">
 3750        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
 3751        /// getting the blob's tags.  Note that TagConditions is currently the
 3752        /// only condition supported by GetTags.
 3753        /// </param>
 3754        /// <param name="cancellationToken">
 3755        /// Optional <see cref="CancellationToken"/> to propagate
 3756        /// notifications that the operation should be cancelled.
 3757        /// </param>
 3758        /// <returns>
 3759        /// A <see cref="Response{Tags}"/> on successfully getting tags.
 3760        /// </returns>
 3761        /// <remarks>
 3762        /// A <see cref="RequestFailedException"/> will be thrown if
 3763        /// a failure occurs.
 3764        /// </remarks>
 3765        public virtual Response<GetBlobTagResult> GetTags(
 3766            BlobRequestConditions conditions = default,
 3767            CancellationToken cancellationToken = default) =>
 3768            GetTagsInternal(
 3769                conditions: conditions,
 3770                async: false,
 3771                cancellationToken: cancellationToken)
 3772            .EnsureCompleted();
 3773
 3774        /// <summary>
 3775        /// Gets the tags associated with the underlying blob.
 3776        ///
 3777        /// For more information, see
 3778        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/get-blob-tags">
 3779        /// Get Blob Tags</see>
 3780        /// </summary>
 3781        /// <param name="conditions">
 3782        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
 3783        /// getting the blob's tags.  Note that TagConditions is currently the
 3784        /// only condition supported by GetTags.
 3785        /// </param>
 3786        /// <param name="cancellationToken">
 3787        /// Optional <see cref="CancellationToken"/> to propagate
 3788        /// notifications that the operation should be cancelled.
 3789        /// </param>
 3790        /// <returns>
 3791        /// A <see cref="Response{Tags}"/> on successfully getting tags.
 3792        /// </returns>
 3793        /// <remarks>
 3794        /// A <see cref="RequestFailedException"/> will be thrown if
 3795        /// a failure occurs.
 3796        /// </remarks>
 3797        public virtual async Task<Response<GetBlobTagResult>> GetTagsAsync(
 3798            BlobRequestConditions conditions = default,
 3799            CancellationToken cancellationToken = default) =>
 3800            await GetTagsInternal(
 3801                conditions: conditions,
 3802                async: true,
 3803                cancellationToken: cancellationToken)
 3804            .ConfigureAwait(false);
 3805
 3806        /// <summary>
 3807        /// Gets the tags associated with the underlying blob.
 3808        ///
 3809        /// For more information, see
 3810        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/get-blob-tags">
 3811        /// Get Blob Tags</see>
 3812        /// </summary>
 3813        /// <param name="async">
 3814        /// Whether to invoke the operation asynchronously.
 3815        /// </param>
 3816        /// <param name="conditions">
 3817        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
 3818        /// getting the blob's tags.  Note that TagConditions is currently the
 3819        /// only condition supported by GetTags.
 3820        /// </param>
 3821        /// <param name="cancellationToken">
 3822        /// Optional <see cref="CancellationToken"/> to propagate
 3823        /// notifications that the operation should be cancelled.
 3824        /// </param>
 3825        /// <returns>
 3826        /// A <see cref="Response{Tags}"/> on successfully getting tags.
 3827        /// </returns>
 3828        /// <remarks>
 3829        /// A <see cref="RequestFailedException"/> will be thrown if
 3830        /// a failure occurs.
 3831        /// </remarks>
 3832        private async Task<Response<GetBlobTagResult>> GetTagsInternal(
 3833            bool async,
 3834            BlobRequestConditions conditions,
 3835            CancellationToken cancellationToken)
 3836        {
 3837            using (Pipeline.BeginLoggingScope(nameof(BlobBaseClient)))
 3838            {
 3839                Pipeline.LogMethodEnter(
 3840                    nameof(BlobBaseClient),
 3841                    message:
 3842                    $"{nameof(Uri)}: {Uri}");
 3843
 3844                try
 3845                {
 3846                    Response<BlobTags> response = await BlobRestClient.Blob.GetTagsAsync(
 3847                        clientDiagnostics: ClientDiagnostics,
 3848                        pipeline: Pipeline,
 3849                        resourceUri: Uri,
 3850                        version: Version.ToVersionString(),
 3851                        ifTags: conditions?.TagConditions,
 3852                        async: async,
 3853                        operationName: $"{nameof(BlobBaseClient)}.{nameof(GetTags)}",
 3854                        cancellationToken: cancellationToken)
 3855                        .ConfigureAwait(false);
 3856
 3857                    GetBlobTagResult result = new GetBlobTagResult
 3858                    {
 3859                        Tags = response.Value.ToTagDictionary()
 3860                    };
 3861
 3862                    return Response.FromValue(
 3863                        result,
 3864                        response.GetRawResponse());
 3865                }
 3866                catch (Exception ex)
 3867                {
 3868                    Pipeline.LogException(ex);
 3869                    throw;
 3870                }
 3871                finally
 3872                {
 3873                    Pipeline.LogMethodExit(nameof(BlobBaseClient));
 3874                }
 3875            }
 3876        }
 3877        #endregion
 3878
 3879        #region SetTags
 3880        /// <summary>
 3881        /// Sets tags on the underlying blob.
 3882        /// A blob can have up to 10 tags.  Tag keys must be between 1 and 128 characters.  Tag values must be between 0
 3883        /// Valid tag key and value characters include lower and upper case letters, digits (0-9),
 3884        /// space (' '), plus ('+'), minus ('-'), period ('.'), foward slash ('/'), colon (':'), equals ('='), and under
 3885        ///
 3886        /// For more information, see
 3887        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/set-blob-tags">
 3888        /// Set Blob Tags</see>.
 3889        /// </summary>
 3890        /// <param name="tags">
 3891        /// The tags to set on the blob.
 3892        /// </param>
 3893        /// <param name="conditions">
 3894        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
 3895        /// setting the blob's tags.  Note that TagConditions is currently the
 3896        /// only condition supported by SetTags.
 3897        /// </param>
 3898        /// <param name="cancellationToken">
 3899        /// Optional <see cref="CancellationToken"/> to propagate
 3900        /// notifications that the operation should be cancelled.
 3901        /// </param>
 3902        /// <returns>
 3903        /// A <see cref="Response"/> on successfully setting the blob tags..
 3904        /// </returns>
 3905        /// <remarks>
 3906        /// A <see cref="RequestFailedException"/> will be thrown if
 3907        /// a failure occurs.
 3908        /// </remarks>
 3909        public virtual Response SetTags(
 3910            Tags tags,
 3911            BlobRequestConditions conditions = default,
 3912            CancellationToken cancellationToken = default) =>
 3913            SetTagsInternal(
 3914                tags: tags,
 3915                conditions: conditions,
 3916                async: false,
 3917                cancellationToken: cancellationToken)
 3918            .EnsureCompleted();
 3919
 3920        /// <summary>
 3921        /// Sets tags on the underlying blob.
 3922        /// A blob can have up to 10 tags.  Tag keys must be between 1 and 128 characters.  Tag values must be between 0
 3923        /// Valid tag key and value characters include lower and upper case letters, digits (0-9),
 3924        /// space (' '), plus ('+'), minus ('-'), period ('.'), foward slash ('/'), colon (':'), equals ('='), and under
 3925        ///
 3926        /// For more information, see
 3927        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/set-blob-tags">
 3928        /// Set Blob Tags</see>.
 3929        /// </summary>
 3930        /// <param name="tags">
 3931        /// The tags to set on the blob.
 3932        /// </param>
 3933        /// <param name="conditions">
 3934        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
 3935        /// setting the blob's tags.  Note that TagConditions is currently the
 3936        /// only condition supported by SetTags.
 3937        /// </param>
 3938        /// <param name="cancellationToken">
 3939        /// Optional <see cref="CancellationToken"/> to propagate
 3940        /// notifications that the operation should be cancelled.
 3941        /// </param>
 3942        /// <returns>
 3943        /// A <see cref="Response"/> on successfully setting the blob tags..
 3944        /// </returns>
 3945        /// <remarks>
 3946        /// A <see cref="RequestFailedException"/> will be thrown if
 3947        /// a failure occurs.
 3948        /// </remarks>
 3949        public virtual async Task<Response> SetTagsAsync(
 3950            Tags tags,
 3951            BlobRequestConditions conditions = default,
 3952            CancellationToken cancellationToken = default) =>
 3953            await SetTagsInternal(
 3954                tags: tags,
 3955                conditions: conditions,
 3956                async: true,
 3957                cancellationToken: cancellationToken)
 3958            .ConfigureAwait(false);
 3959
 3960        /// <summary>
 3961        /// Sets tags on the underlying blob.
 3962        /// A blob can have up to 10 tags.  Tag keys must be between 1 and 128 characters.  Tag values must be between 0
 3963        /// Valid tag key and value characters include lower and upper case letters, digits (0-9),
 3964        /// space (' '), plus ('+'), minus ('-'), period ('.'), foward slash ('/'), colon (':'), equals ('='), and under
 3965        ///
 3966        /// For more information, see
 3967        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/set-blob-tags">
 3968        /// Set Blob Tags</see>.
 3969        /// </summary>
 3970        /// <param name="tags">
 3971        /// The tags to set on the blob.
 3972        /// </param>
 3973        /// <param name="conditions">
 3974        /// Optional <see cref="BlobRequestConditions"/> to add conditions on
 3975        /// setting the blob's tags.  Note that TagConditions is currently the
 3976        /// only condition supported by SetTags.
 3977        /// </param>
 3978        /// <param name="async">
 3979        /// Whether to invoke the operation asynchronously.
 3980        /// </param>
 3981        /// <param name="cancellationToken">
 3982        /// Optional <see cref="CancellationToken"/> to propagate
 3983        /// notifications that the operation should be cancelled.
 3984        /// </param>
 3985        /// <returns>
 3986        /// A <see cref="Response"/> on successfully setting the blob tags..
 3987        /// </returns>
 3988        /// <remarks>
 3989        /// A <see cref="RequestFailedException"/> will be thrown if
 3990        /// a failure occurs.
 3991        /// </remarks>
 3992        //TODO what about content CRC and content MD5?
 3993        private async Task<Response> SetTagsInternal(
 3994            Tags tags,
 3995            BlobRequestConditions conditions,
 3996            bool async,
 3997            CancellationToken cancellationToken)
 3998        {
 3999            using (Pipeline.BeginLoggingScope(nameof(BlobBaseClient)))
 4000            {
 4001                Pipeline.LogMethodEnter(
 4002                    nameof(BlobBaseClient),
 4003                    message:
 4004                    $"{nameof(Uri)}: {Uri}\n" +
 4005                    $"{nameof(tags)}: {tags}");
 4006                try
 4007                {
 4008                    return await BlobRestClient.Blob.SetTagsAsync(
 4009                        clientDiagnostics: ClientDiagnostics,
 4010                        pipeline: Pipeline,
 4011                        resourceUri: Uri,
 4012                        version: Version.ToVersionString(),
 4013                        tags: tags.ToBlobTags(),
 4014                        ifTags: conditions?.TagConditions,
 4015                        async: async,
 4016                        operationName: $"{nameof(BlobBaseClient)}.{nameof(SetTags)}",
 4017                        cancellationToken: cancellationToken)
 4018                        .ConfigureAwait(false);
 4019                }
 4020                catch (Exception ex)
 4021                {
 4022                    Pipeline.LogException(ex);
 4023                    throw;
 4024                }
 4025                finally
 4026                {
 4027                    Pipeline.LogMethodExit(nameof(BlobBaseClient));
 4028                }
 4029            }
 4030        }
 4031        #endregion
 4032    }
 4033
 4034    /// <summary>
 4035    /// Add easy to discover methods to <see cref="BlobContainerClient"/> for
 4036    /// creating <see cref="BlobBaseClient"/> instances.
 4037    /// </summary>
 4038    public static partial class SpecializedBlobExtensions
 4039    {
 4040        /// <summary>
 4041        /// Create a new <see cref="BlobBaseClient"/> object by concatenating
 4042        /// <paramref name="blobName"/> to the end of the
 4043        /// <paramref name="client"/>'s <see cref="BlobContainerClient.Uri"/>.
 4044        /// The new <see cref="BlobBaseClient"/> uses the same request policy
 4045        /// pipeline as the <see cref="BlobContainerClient"/>.
 4046        /// </summary>
 4047        /// <param name="client">The <see cref="BlobContainerClient"/>.</param>
 4048        /// <param name="blobName">The name of the blob.</param>
 4049        /// <returns>A new <see cref="BlobBaseClient"/> instance.</returns>
 4050        public static BlobBaseClient GetBlobBaseClient(
 4051            this BlobContainerClient client,
 4052            string blobName) =>
 84053            new BlobBaseClient(
 84054                client.Uri.AppendToPath(blobName),
 84055                client.Pipeline,
 84056                client.Version,
 84057                client.ClientDiagnostics,
 84058                client.CustomerProvidedKey,
 84059                client.ClientSideEncryption,
 84060                client.EncryptionScope);
 4061
 4062        /// <summary>
 4063        /// Creates a new instance of the <see cref="BlobClient"/> class, maintaining all the same
 4064        /// internals but specifying new <see cref="ClientSideEncryptionOptions"/>.
 4065        /// </summary>
 4066        /// <param name="client">Client to base off of.</param>
 4067        /// <param name="clientSideEncryptionOptions">New encryption options. Setting this to <code>default</code> will 
 4068        /// <returns>New instance with provided options and same internals otherwise.</returns>
 4069        public static BlobClient WithClientSideEncryptionOptions(this BlobClient client, ClientSideEncryptionOptions cli
 04070            => new BlobClient(
 04071                client.Uri,
 04072                client.Pipeline,
 04073                client.Version,
 04074                client.ClientDiagnostics,
 04075                client.CustomerProvidedKey,
 04076                clientSideEncryptionOptions,
 04077                client.EncryptionScope);
 4078    }
 4079}

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

#LineLine coverage
 1// Copyright (c) Microsoft Corporation. All rights reserved.
 2// Licensed under the MIT License.
 3
 4using System;
 5using System.ComponentModel;
 6using System.Threading;
 7using System.Threading.Tasks;
 8using Azure.Core.Pipeline;
 9using Azure.Storage.Blobs.Models;
 10
 11#pragma warning disable SA1402  // File may only contain a single type
 12
 13namespace Azure.Storage.Blobs.Specialized
 14{
 15    /// <summary>
 16    /// The <see cref="BlobLeaseClient"/> allows you to manipulate Azure
 17    /// Storage leases on containers and blobs.
 18    /// </summary>
 19    public class BlobLeaseClient
 20    {
 21        /// <summary>
 22        /// The <see cref="BlobClient"/> to manage leases for.
 23        /// </summary>
 24        private readonly BlobBaseClient _blob;
 25
 26        /// <summary>
 27        /// Gets the <see cref="BlobClient"/> to manage leases for.
 28        /// </summary>
 29        protected virtual BlobBaseClient BlobClient => _blob;
 30
 31        /// <summary>
 32        /// The <see cref="BlobContainerClient"/> to manage leases for.
 33        /// </summary>
 34        private readonly BlobContainerClient _container;
 35
 36        /// <summary>
 37        /// Gets the <see cref="BlobContainerClient"/> to manage leases for.
 38        /// </summary>
 39        protected virtual BlobContainerClient BlobContainerClient => _container;
 40
 41        /// <summary>
 42        /// Gets the URI of the object being leased.
 43        /// </summary>
 44        public Uri Uri => BlobClient?.Uri ?? BlobContainerClient?.Uri;
 45
 46        /// <summary>
 47        /// Gets the Lease ID for this lease.
 48        /// </summary>
 49        public virtual string LeaseId { get; private set; }
 50
 51        /// <summary>
 52        /// The <see cref="HttpPipeline"/> transport pipeline used to send
 53        /// every request.
 54        /// </summary>
 55        private HttpPipeline Pipeline => BlobClient?.Pipeline ?? BlobContainerClient.Pipeline;
 56
 57        /// <summary>
 58        /// The version of the service to use when sending requests.
 59        /// </summary>
 60        internal virtual BlobClientOptions.ServiceVersion Version => BlobClient?.Version ?? BlobContainerClient.Version;
 61
 62        /// <summary>
 63        /// The <see cref="ClientDiagnostics"/> instance used to create diagnostic scopes
 64        /// every request.
 65        /// </summary>
 66        internal virtual ClientDiagnostics ClientDiagnostics => BlobClient?.ClientDiagnostics ?? BlobContainerClient.Cli
 67
 68        /// <summary>
 69        /// The <see cref="TimeSpan"/> representing an infinite lease duration.
 70        /// </summary>
 71        public static readonly TimeSpan InfiniteLeaseDuration = TimeSpan.FromSeconds(Constants.Blob.Lease.InfiniteLeaseD
 72
 73        /// <summary>
 74        /// Initializes a new instance of the <see cref="BlobLeaseClient"/> class
 75        /// for mocking.
 76        /// </summary>
 77        protected BlobLeaseClient()
 78        {
 79            _blob = null;
 80            _container = null;
 81        }
 82
 83        /// <summary>
 84        /// Initializes a new instance of the <see cref="BlobLeaseClient"/>  class.
 85        /// </summary>
 86        /// <param name="client">
 87        /// A <see cref="BlobClient"/> representing the blob being leased.
 88        /// </param>
 89        /// <param name="leaseId">
 90        /// An optional lease ID.  If no lease ID is provided, a random lease
 91        /// ID will be created.
 92        /// </param>
 93        public BlobLeaseClient(BlobBaseClient client, string leaseId = null)
 94        {
 95            _blob = client ?? throw Errors.ArgumentNull(nameof(client));
 96            _container = null;
 97            LeaseId = leaseId ?? CreateUniqueLeaseId();
 98        }
 99
 100        /// <summary>
 101        /// Initializes a new instance of the <see cref="BlobLeaseClient"/>  class.
 102        /// </summary>
 103        /// <param name="client">
 104        /// A <see cref="BlobContainerClient"/> representing the blob container
 105        /// being leased.
 106        /// </param>
 107        /// <param name="leaseId">
 108        /// An optional lease ID.  If no lease ID is provided, a random lease
 109        /// ID will be created.
 110        /// </param>
 111        public BlobLeaseClient(BlobContainerClient client, string leaseId = null)
 112        {
 113            _blob = null;
 114            _container = client ?? throw Errors.ArgumentNull(nameof(client));
 115            LeaseId = leaseId ?? CreateUniqueLeaseId();
 116        }
 117
 118        /// <summary>
 119        /// Gets a unique lease ID.
 120        /// </summary>
 121        /// <returns>A unique lease ID.</returns>
 122        private static string CreateUniqueLeaseId() => Guid.NewGuid().ToString();
 123
 124        /// <summary>
 125        /// Ensure either the Blob or Container is present.
 126        /// </summary>
 127        private void EnsureClient()
 128        {
 129            if (BlobClient == null && BlobContainerClient == null)
 130            {
 131                // This can only happen if someone's not being careful while mocking
 132                throw BlobErrors.BlobOrContainerMissing(nameof(BlobLeaseClient), nameof(BlobBaseClient), nameof(BlobCont
 133            }
 134        }
 135
 136        #region Acquire
 137        /// <summary>
 138        /// The <see cref="Acquire"/> operation acquires a lease on
 139        /// the blob or container.  The lease <paramref name="duration"/> must
 140        /// be between 15 to 60 seconds, or infinite (-1).
 141        ///
 142        /// If the container does not have an active lease, the Blob service
 143        /// creates a lease on the blob or container and returns it.  If the
 144        /// container has an active lease, you can only request a new lease
 145        /// using the active lease ID as <see cref="LeaseId"/>, but you can
 146        /// specify a new <paramref name="duration"/>.
 147        ///
 148        /// For more information, see <see href="https://docs.microsoft.com/rest/api/storageservices/lease-container" />
 149        /// </summary>
 150        /// <param name="duration">
 151        /// Specifies the duration of the lease, in seconds, or specify
 152        /// <see cref="InfiniteLeaseDuration"/> for a lease that never expires.
 153        /// A non-infinite lease can be between 15 and 60 seconds.
 154        /// A lease duration cannot be changed using <see cref="RenewAsync"/>
 155        /// or <see cref="ChangeAsync"/>.
 156        /// </param>
 157        /// <param name="conditions">
 158        /// Optional <see cref="BlobLeaseRequestConditions"/> to add
 159        /// conditions on acquiring a lease.
 160        /// </param>
 161        /// <param name="cancellationToken">
 162        /// Optional <see cref="CancellationToken"/> to propagate
 163        /// notifications that the operation should be cancelled.
 164        /// </param>
 165        /// <returns>
 166        /// A <see cref="Response{Lease}"/> describing the lease.
 167        /// </returns>
 168        /// <remarks>
 169        /// A <see cref="RequestFailedException"/> will be thrown if
 170        /// a failure occurs.
 171        /// </remarks>
 172        public virtual Response<BlobLease> Acquire(
 173            TimeSpan duration,
 174            RequestConditions conditions = default,
 175            CancellationToken cancellationToken = default) =>
 176            AcquireInternal(
 177                duration,
 178                conditions,
 179                async: false,
 180                cancellationToken)
 181                .EnsureCompleted();
 182
 183        /// <summary>
 184        /// The <see cref="Acquire"/> operation acquires a lease on
 185        /// the blob or container.  The lease <paramref name="duration"/> must
 186        /// be between 15 to 60 seconds, or infinite (-1).
 187        ///
 188        /// If the container does not have an active lease, the Blob service
 189        /// creates a lease on the blob or container and returns it.  If the
 190        /// container has an active lease, you can only request a new lease
 191        /// using the active lease ID as <see cref="LeaseId"/>, but you can
 192        /// specify a new <paramref name="duration"/>.
 193        ///
 194        /// For more information, see
 195        /// <see href="https://docs.microsoft.com/rest/api/storageservices/lease-container">
 196        /// Lease Container</see>.
 197        /// </summary>
 198        /// <param name="duration">
 199        /// Specifies the duration of the lease, in seconds, or specify
 200        /// <see cref="InfiniteLeaseDuration"/> for a lease that never expires.
 201        /// A non-infinite lease can be between 15 and 60 seconds.
 202        /// A lease duration cannot be changed using <see cref="RenewAsync"/>
 203        /// or <see cref="ChangeAsync"/>.
 204        /// </param>
 205        /// <param name="conditions">
 206        /// Optional <see cref="BlobLeaseRequestConditions"/> to add
 207        /// conditions on acquiring a lease.
 208        /// </param>
 209        /// <param name="cancellationToken">
 210        /// Optional <see cref="CancellationToken"/> to propagate
 211        /// notifications that the operation should be cancelled.
 212        /// </param>
 213        /// <returns>
 214        /// A <see cref="Response{Lease}"/> describing the lease.
 215        /// </returns>
 216        /// <remarks>
 217        /// A <see cref="RequestFailedException"/> will be thrown if
 218        /// a failure occurs.
 219        /// </remarks>
 220        public virtual async Task<Response<BlobLease>> AcquireAsync(
 221            TimeSpan duration,
 222            RequestConditions conditions = default,
 223            CancellationToken cancellationToken = default) =>
 224            await AcquireInternal(
 225                duration,
 226                conditions,
 227                async: true,
 228                cancellationToken)
 229                .ConfigureAwait(false);
 230
 231        /// <summary>
 232        /// The <see cref="AcquireInternal"/> operation acquires a lease on
 233        /// the blob or container.  The lease <paramref name="duration"/> must
 234        /// be between 15 to 60 seconds, or infinite (-1).
 235        ///
 236        /// If the container does not have an active lease, the Blob service
 237        /// creates a lease on the blob or container and returns it.  If the
 238        /// container has an active lease, you can only request a new lease
 239        /// using the active lease ID as <see cref="LeaseId"/>, but you can
 240        /// specify a new <paramref name="duration"/>.
 241        ///
 242        /// For more information, see
 243        /// <see href="https://docs.microsoft.com/rest/api/storageservices/lease-container">
 244        /// Lease Container</see>.
 245        /// </summary>
 246        /// <param name="duration">
 247        /// Specifies the duration of the lease, in seconds, or specify
 248        /// <see cref="InfiniteLeaseDuration"/> for a lease that never expires.
 249        /// A non-infinite lease can be between 15 and 60 seconds.
 250        /// A lease duration cannot be changed using <see cref="RenewAsync"/>
 251        /// or <see cref="ChangeAsync"/>.
 252        /// </param>
 253        /// <param name="conditions">
 254        /// Optional <see cref="BlobLeaseRequestConditions"/> to add
 255        /// conditions on acquiring a lease.
 256        /// </param>
 257        /// <param name="async">
 258        /// Whether to invoke the operation asynchronously.
 259        /// </param>
 260        /// <param name="cancellationToken">
 261        /// Optional <see cref="CancellationToken"/> to propagate
 262        /// notifications that the operation should be cancelled.
 263        /// </param>
 264        /// <returns>
 265        /// A <see cref="Response{Lease}"/> describing the lease.
 266        /// </returns>
 267        /// <remarks>
 268        /// A <see cref="RequestFailedException"/> will be thrown if
 269        /// a failure occurs.
 270        /// </remarks>
 271        private async Task<Response<BlobLease>> AcquireInternal(
 272            TimeSpan duration,
 273            RequestConditions conditions,
 274            bool async,
 275            CancellationToken cancellationToken)
 276        {
 277            EnsureClient();
 278            // Int64 is an overflow safe cast relative to TimeSpan.MaxValue
 279            var serviceDuration = duration < TimeSpan.Zero ? Constants.Blob.Lease.InfiniteLeaseDuration : Convert.ToInt6
 280            using (Pipeline.BeginLoggingScope(nameof(BlobLeaseClient)))
 281            {
 282                Pipeline.LogMethodEnter(
 283                    nameof(BlobLeaseClient),
 284                    message:
 285                    $"{nameof(Uri)}: {Uri}\n" +
 286                    $"{nameof(LeaseId)}: {LeaseId}\n" +
 287                    $"{nameof(duration)}: {duration}");
 288                try
 289                {
 290                    string tagCondition = null;
 291                    if (conditions is BlobLeaseRequestConditions leaseConditions)
 292                    {
 293                        tagCondition = leaseConditions?.TagConditions;
 294                    }
 295
 296                    if (BlobClient != null)
 297                    {
 298                        return await BlobRestClient.Blob.AcquireLeaseAsync(
 299                            ClientDiagnostics,
 300                            Pipeline,
 301                            Uri,
 302                            version: Version.ToVersionString(),
 303                            duration: serviceDuration,
 304                            proposedLeaseId: LeaseId,
 305                            ifModifiedSince: conditions?.IfModifiedSince,
 306                            ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
 307                            ifMatch: conditions?.IfMatch,
 308                            ifNoneMatch: conditions?.IfNoneMatch,
 309                            ifTags: tagCondition,
 310                            async: async,
 311                            operationName: $"{nameof(BlobLeaseClient)}.{nameof(Acquire)}",
 312                            cancellationToken: cancellationToken)
 313                            .ConfigureAwait(false);
 314                    }
 315                    else
 316                    {
 317                        if (conditions?.IfMatch != default || conditions?.IfNoneMatch != default)
 318                        {
 319                            throw BlobErrors.BlobConditionsMustBeDefault(
 320                                nameof(conditions.IfMatch),
 321                                nameof(conditions.IfNoneMatch));
 322                        }
 323                        return await BlobRestClient.Container.AcquireLeaseAsync(
 324                            ClientDiagnostics,
 325                            Pipeline,
 326                            Uri,
 327                            version: Version.ToVersionString(),
 328                            duration: serviceDuration,
 329                            proposedLeaseId: LeaseId,
 330                            ifModifiedSince: conditions?.IfModifiedSince,
 331                            ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
 332                            async: async,
 333                            operationName: $"{nameof(BlobLeaseClient)}.{nameof(Acquire)}",
 334                            cancellationToken: cancellationToken)
 335                            .ConfigureAwait(false);
 336                    }
 337                }
 338                catch (Exception ex)
 339                {
 340                    Pipeline.LogException(ex);
 341                    throw;
 342                }
 343                finally
 344                {
 345                    Pipeline.LogMethodExit(nameof(BlobLeaseClient));
 346                }
 347            }
 348        }
 349        #endregion Acquire
 350
 351        #region Renew
 352        /// <summary>
 353        /// The <see cref="Renew"/> operation renews the blob or
 354        /// container's previously-acquired lease.
 355        ///
 356        /// The lease can be renewed if the leaseId
 357        /// matches that associated with the blob or container.  Note that the]
 358        /// lease may be renewed even if it has expired as long as the blob or
 359        /// container has not been leased again since the expiration of that
 360        /// lease.  When you renew a lease, the lease duration clock resets.
 361        ///
 362        /// For more information, see
 363        /// <see href="https://docs.microsoft.com/rest/api/storageservices/lease-container">
 364        /// Lease Container</see>.
 365        /// </summary>
 366        /// <param name="conditions">
 367        /// Optional <see cref="BlobLeaseRequestConditions"/> to add
 368        /// conditions on renewing a lease.
 369        /// </param>
 370        /// <param name="cancellationToken">
 371        /// Optional <see cref="CancellationToken"/> to propagate
 372        /// notifications that the operation should be cancelled.
 373        /// </param>
 374        /// <returns>
 375        /// A <see cref="Response{Lease}"/> describing the lease.
 376        /// </returns>
 377        /// <remarks>
 378        /// A <see cref="RequestFailedException"/> will be thrown if
 379        /// a failure occurs.
 380        /// </remarks>
 381        public virtual Response<BlobLease> Renew(
 382            RequestConditions conditions = default,
 383            CancellationToken cancellationToken = default) =>
 384            RenewInternal(
 385                conditions,
 386                false, // async
 387                cancellationToken)
 388                .EnsureCompleted();
 389
 390        /// <summary>
 391        /// The <see cref="RenewAsync"/> operation renews the blob or
 392        /// container's previously-acquired lease.
 393        ///
 394        /// The lease can be renewed if the leaseId
 395        /// matches that associated with the blob or container.  Note that the]
 396        /// lease may be renewed even if it has expired as long as the blob or
 397        /// container has not been leased again since the expiration of that
 398        /// lease.  When you renew a lease, the lease duration clock resets.
 399        ///
 400        /// For more information, see
 401        /// <see href="https://docs.microsoft.com/rest/api/storageservices/lease-container">
 402        /// Lease Container</see>.
 403        /// </summary>
 404        /// <param name="conditions">
 405        /// Optional <see cref="BlobLeaseRequestConditions"/> to add
 406        /// conditions on renewing a lease.
 407        /// </param>
 408        /// <param name="cancellationToken">
 409        /// Optional <see cref="CancellationToken"/> to propagate
 410        /// notifications that the operation should be cancelled.
 411        /// </param>
 412        /// <returns>
 413        /// A <see cref="Response{Lease}"/> describing the lease.
 414        /// </returns>
 415        /// <remarks>
 416        /// A <see cref="RequestFailedException"/> will be thrown if
 417        /// a failure occurs.
 418        /// </remarks>
 419        public virtual async Task<Response<BlobLease>> RenewAsync(
 420            RequestConditions conditions = default,
 421            CancellationToken cancellationToken = default) =>
 422            await RenewInternal(
 423                conditions,
 424                true, // async
 425                cancellationToken)
 426                .ConfigureAwait(false);
 427
 428        /// <summary>
 429        /// The <see cref="RenewInternal"/> operation renews the blob or
 430        /// container's previously-acquired lease.
 431        ///
 432        /// The lease can be renewed if the leaseId
 433        /// matches that associated with the blob or container.  Note that the]
 434        /// lease may be renewed even if it has expired as long as the blob or
 435        /// container has not been leased again since the expiration of that
 436        /// lease.  When you renew a lease, the lease duration clock resets.
 437        ///
 438        /// For more information, see
 439        /// <see href="https://docs.microsoft.com/rest/api/storageservices/lease-container">
 440        /// Lease Container</see>.
 441        /// </summary>
 442        /// <param name="conditions">
 443        /// Optional <see cref="BlobLeaseRequestConditions"/> to add
 444        /// conditions on renewing a lease.
 445        /// </param>
 446        /// <param name="async">
 447        /// Whether to invoke the operation asynchronously.
 448        /// </param>
 449        /// <param name="cancellationToken">
 450        /// Optional <see cref="CancellationToken"/> to propagate
 451        /// notifications that the operation should be cancelled.
 452        /// </param>
 453        /// <returns>
 454        /// A <see cref="Response{Lease}"/> describing the lease.
 455        /// </returns>
 456        /// <remarks>
 457        /// A <see cref="RequestFailedException"/> will be thrown if
 458        /// a failure occurs.
 459        /// </remarks>
 460        private async Task<Response<BlobLease>> RenewInternal(
 461            RequestConditions conditions,
 462            bool async,
 463            CancellationToken cancellationToken)
 464        {
 465            using (Pipeline.BeginLoggingScope(nameof(BlobLeaseClient)))
 466            {
 467                Pipeline.LogMethodEnter(
 468                    nameof(BlobLeaseClient),
 469                    message:
 470                    $"{nameof(Uri)}: {Uri}\n" +
 471                    $"{nameof(LeaseId)}: {LeaseId}\n" +
 472                    $"{nameof(conditions)}: {conditions}");
 473                try
 474                {
 475                    string tagConditions = null;
 476                    if (conditions != null && conditions.GetType() == typeof(BlobLeaseRequestConditions))
 477                    {
 478                        tagConditions = ((BlobLeaseRequestConditions)conditions).TagConditions;
 479                    }
 480
 481                    if (BlobClient != null)
 482                    {
 483                        return await BlobRestClient.Blob.RenewLeaseAsync(
 484                            ClientDiagnostics,
 485                            Pipeline,
 486                            Uri,
 487                            leaseId: LeaseId,
 488                            version: Version.ToVersionString(),
 489                            ifModifiedSince: conditions?.IfModifiedSince,
 490                            ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
 491                            ifMatch: conditions?.IfMatch,
 492                            ifNoneMatch: conditions?.IfNoneMatch,
 493                            ifTags: tagConditions,
 494                            async: async,
 495                            operationName: $"{nameof(BlobLeaseClient)}.{nameof(Renew)}",
 496                            cancellationToken: cancellationToken)
 497                            .ConfigureAwait(false);
 498                    }
 499                    else
 500                    {
 501                        if (conditions?.IfMatch != default || conditions?.IfNoneMatch != default)
 502                        {
 503                            throw BlobErrors.BlobConditionsMustBeDefault(
 504                                nameof(conditions.IfMatch),
 505                                nameof(conditions.IfNoneMatch));
 506                        }
 507                        return await BlobRestClient.Container.RenewLeaseAsync(
 508                            ClientDiagnostics,
 509                            Pipeline,
 510                            Uri,
 511                            leaseId: LeaseId,
 512                            version: Version.ToVersionString(),
 513                            ifModifiedSince: conditions?.IfModifiedSince,
 514                            ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
 515                            async: async,
 516                            operationName: $"{nameof(BlobLeaseClient)}.{nameof(Renew)}",
 517                            cancellationToken: cancellationToken)
 518                            .ConfigureAwait(false);
 519                    }
 520                }
 521                catch (Exception ex)
 522                {
 523                    Pipeline.LogException(ex);
 524                    throw;
 525                }
 526                finally
 527                {
 528                    Pipeline.LogMethodExit(nameof(BlobLeaseClient));
 529                }
 530            }
 531        }
 532        #endregion Renew
 533
 534        #region Release
 535        /// <summary>
 536        /// The <see cref="Release"/> operation releases the
 537        /// container or blob's previously-acquired lease.
 538        ///
 539        /// The lease may be released if the <see cref="LeaseId"/>
 540        /// matches that associated with the container or blob.  Releasing the
 541        /// lease allows another client to immediately acquire the lease for the
 542        /// container or blob as soon as the release is complete.
 543        ///
 544        /// For more information, see
 545        /// <see href="https://docs.microsoft.com/rest/api/storageservices/lease-container">
 546        /// Lease Container</see>.
 547        /// </summary>
 548        /// <param name="conditions">
 549        /// Optional <see cref="BlobLeaseRequestConditions"/> to add
 550        /// conditions on releasing a lease.
 551        /// </param>
 552        /// <param name="cancellationToken">
 553        /// Optional <see cref="CancellationToken"/> to propagate
 554        /// notifications that the operation should be cancelled.
 555        /// </param>
 556        /// <returns>
 557        /// A <see cref="Response{ReleaseObjectLeaseInfo}"/> describing the
 558        /// updated blob or container.
 559        /// </returns>
 560        /// <remarks>
 561        /// A <see cref="RequestFailedException"/> will be thrown if
 562        /// a failure occurs.
 563        /// </remarks>
 564        public virtual Response<ReleasedObjectInfo> Release(
 565            RequestConditions conditions = default,
 566            CancellationToken cancellationToken = default) =>
 567            ReleaseInternal(
 568                conditions,
 569                false, // async
 570                cancellationToken)
 571                .EnsureCompleted();
 572
 573        /// <summary>
 574        /// The <see cref="ReleaseAsync"/> operation releases the
 575        /// container or blob's previously-acquired lease.
 576        ///
 577        /// The lease may be released if the <see cref="LeaseId"/>
 578        /// matches that associated with the container or blob.  Releasing the
 579        /// lease allows another client to immediately acquire the lease for the
 580        /// container or blob as soon as the release is complete.
 581        ///
 582        /// For more information, see
 583        /// <see href="https://docs.microsoft.com/rest/api/storageservices/lease-container">
 584        /// Lease Container</see>.
 585        /// </summary>
 586        /// <param name="conditions">
 587        /// Optional <see cref="BlobLeaseRequestConditions"/> to add
 588        /// conditions on releasing a lease.
 589        /// </param>
 590        /// <param name="cancellationToken">
 591        /// Optional <see cref="CancellationToken"/> to propagate
 592        /// notifications that the operation should be cancelled.
 593        /// </param>
 594        /// <returns>
 595        /// A <see cref="Response{ReleasedObjectInfo}"/> describing the
 596        /// updated blob or container.
 597        /// </returns>
 598        /// <remarks>
 599        /// A <see cref="RequestFailedException"/> will be thrown if
 600        /// a failure occurs.
 601        /// </remarks>
 602        public virtual async Task<Response<ReleasedObjectInfo>> ReleaseAsync(
 603            RequestConditions conditions = default,
 604            CancellationToken cancellationToken = default) =>
 605            await ReleaseInternal(
 606                conditions,
 607                true, // async
 608                cancellationToken)
 609                .ConfigureAwait(false);
 610
 611        /// <summary>
 612        /// The <see cref="ReleaseInternal"/> operation releases the
 613        /// container or blob's previously-acquired lease.
 614        ///
 615        /// The lease may be released if the <see cref="LeaseId"/>
 616        /// matches that associated with the container or blob.  Releasing the
 617        /// lease allows another client to immediately acquire the lease for the
 618        /// container or blob as soon as the release is complete.
 619        ///
 620        /// For more information, see
 621        /// <see href="https://docs.microsoft.com/rest/api/storageservices/lease-container">
 622        /// Lease Container</see>.
 623        /// </summary>
 624        /// <param name="conditions">
 625        /// Optional <see cref="BlobLeaseRequestConditions"/> to add
 626        /// conditions on releasing a lease.
 627        /// </param>
 628        /// <param name="async">
 629        /// Whether to invoke the operation asynchronously.
 630        /// </param>
 631        /// <param name="cancellationToken">
 632        /// Optional <see cref="CancellationToken"/> to propagate
 633        /// notifications that the operation should be cancelled.
 634        /// </param>
 635        /// <returns>
 636        /// A <see cref="Response{ReleasedObjectInfo}"/> describing the
 637        /// updated blob or container.
 638        /// </returns>
 639        /// <remarks>
 640        /// A <see cref="RequestFailedException"/> will be thrown if
 641        /// a failure occurs.
 642        /// </remarks>
 643        [EditorBrowsable(EditorBrowsableState.Never)]
 644        public virtual async Task<Response<ReleasedObjectInfo>> ReleaseInternal(
 645            RequestConditions conditions,
 646#pragma warning disable AZC0105 // DO NOT add 'async' parameter to public methods. This method is published, so it can't
 647            bool async,
 648#pragma warning restore AZC0105 // DO NOT add 'async' parameter to public methods.
 649            CancellationToken cancellationToken)
 650        {
 651            EnsureClient();
 652            using (Pipeline.BeginLoggingScope(nameof(BlobLeaseClient)))
 653            {
 654                Pipeline.LogMethodEnter(
 655                    nameof(BlobLeaseClient),
 656                    message:
 657                    $"{nameof(Uri)}: {Uri}\n" +
 658                    $"{nameof(LeaseId)}: {LeaseId}\n" +
 659                    $"{nameof(conditions)}: {conditions}");
 660                try
 661                {
 662                    string tagConditions = default;
 663
 664                    if (conditions != null && conditions.GetType() == typeof(BlobLeaseRequestConditions))
 665                    {
 666                        tagConditions = ((BlobLeaseRequestConditions)conditions).TagConditions;
 667                    }
 668
 669                    if (BlobClient != null)
 670                    {
 671                        Response<BlobInfo> response =
 672                            await BlobRestClient.Blob.ReleaseLeaseAsync(
 673                                ClientDiagnostics,
 674                                Pipeline,
 675                                Uri,
 676                                leaseId: LeaseId,
 677                                version: Version.ToVersionString(),
 678                                ifModifiedSince: conditions?.IfModifiedSince,
 679                                ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
 680                                ifMatch: conditions?.IfMatch,
 681                                ifNoneMatch: conditions?.IfNoneMatch,
 682                                ifTags: tagConditions,
 683                                async: async,
 684                                operationName: $"{nameof(BlobLeaseClient)}.{nameof(Release)}",
 685                                cancellationToken: cancellationToken)
 686                                .ConfigureAwait(false);
 687                        return Response.FromValue(new ReleasedObjectInfo(response.Value), response.GetRawResponse());
 688                    }
 689                    else
 690                    {
 691                        if (conditions?.IfMatch != default || conditions?.IfNoneMatch != default)
 692                        {
 693                            throw BlobErrors.BlobConditionsMustBeDefault(
 694                                nameof(RequestConditions.IfMatch),
 695                                nameof(RequestConditions.IfNoneMatch));
 696                        }
 697                        Response<BlobContainerInfo> response =
 698                            await BlobRestClient.Container.ReleaseLeaseAsync(
 699                                ClientDiagnostics,
 700                                Pipeline,
 701                                Uri,
 702                                leaseId: LeaseId,
 703                                version: Version.ToVersionString(),
 704                                ifModifiedSince: conditions?.IfModifiedSince,
 705                                ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
 706                                async: async,
 707                                operationName: $"{nameof(BlobLeaseClient)}.{nameof(Release)}",
 708                                cancellationToken: cancellationToken)
 709                                .ConfigureAwait(false);
 710                        return Response.FromValue(new ReleasedObjectInfo(response.Value), response.GetRawResponse());
 711                    }
 712                }
 713                catch (Exception ex)
 714                {
 715                    Pipeline.LogException(ex);
 716                    throw;
 717                }
 718                finally
 719                {
 720                    Pipeline.LogMethodExit(nameof(BlobLeaseClient));
 721                }
 722            }
 723        }
 724        #endregion Release
 725
 726        #region Change
 727        /// <summary>
 728        /// The <see cref="Change"/> operation changes the lease
 729        /// of an active lease.  A change must include the current
 730        /// <see cref="LeaseId"/> and a new <paramref name="proposedId"/>.
 731        ///
 732        /// For more information, see
 733        /// <see href="https://docs.microsoft.com/rest/api/storageservices/lease-container">
 734        /// Lease Container</see>.
 735        /// </summary>
 736        /// <param name="proposedId">
 737        /// An optional proposed lease ID, in a GUID string format. A
 738        /// <see cref="RequestFailedException"/> will be thrown if the
 739        /// proposed lease ID is not in the correct format.
 740        /// </param>
 741        /// <param name="conditions">
 742        /// Optional <see cref="BlobLeaseRequestConditions"/> to add
 743        /// conditions on changing a lease.
 744        /// </param>
 745        /// <param name="cancellationToken">
 746        /// Optional <see cref="CancellationToken"/> to propagate
 747        /// notifications that the operation should be cancelled.
 748        /// </param>
 749        /// <returns>
 750        /// A <see cref="Response{Lease}"/> describing the lease.
 751        /// </returns>
 752        /// <remarks>
 753        /// A <see cref="RequestFailedException"/> will be thrown if
 754        /// a failure occurs.
 755        /// </remarks>
 756        public virtual Response<BlobLease> Change(
 757            string proposedId,
 758            RequestConditions conditions = default,
 759            CancellationToken cancellationToken = default) =>
 760            ChangeInternal(
 761                proposedId,
 762                conditions,
 763                false, // async
 764                cancellationToken)
 765                .EnsureCompleted();
 766
 767        /// <summary>
 768        /// The <see cref="ChangeAsync"/> operation changes the lease
 769        /// of an active lease.  A change must include the current
 770        /// <see cref="LeaseId"/> and a new <paramref name="proposedId"/>.
 771        ///
 772        /// For more information, see
 773        /// <see href="https://docs.microsoft.com/rest/api/storageservices/lease-container">
 774        /// Lease Container</see>.
 775        /// </summary>
 776        /// <param name="proposedId">
 777        /// An optional proposed lease ID, in a GUID string format. A
 778        /// <see cref="RequestFailedException"/> will be thrown if the
 779        /// proposed lease ID is not in the correct format.
 780        /// </param>
 781        /// <param name="conditions">
 782        /// Optional <see cref="BlobLeaseRequestConditions"/> to add
 783        /// conditions on changing a lease.
 784        /// </param>
 785        /// <param name="cancellationToken">
 786        /// Optional <see cref="CancellationToken"/> to propagate
 787        /// notifications that the operation should be cancelled.
 788        /// </param>
 789        /// <returns>
 790        /// A <see cref="Response{Lease}"/> describing the lease.
 791        /// </returns>
 792        /// <remarks>
 793        /// A <see cref="RequestFailedException"/> will be thrown if
 794        /// a failure occurs.
 795        /// </remarks>
 796        public virtual async Task<Response<BlobLease>> ChangeAsync(
 797            string proposedId,
 798            RequestConditions conditions = default,
 799            CancellationToken cancellationToken = default) =>
 800            await ChangeInternal(
 801                proposedId,
 802                conditions,
 803                true, // async
 804                cancellationToken)
 805                .ConfigureAwait(false);
 806
 807        /// <summary>
 808        /// The <see cref="ChangeInternal"/> operation changes the lease
 809        /// of an active lease.  A change must include the current
 810        /// <see cref="LeaseId"/> and a new <paramref name="proposedId"/>.
 811        ///
 812        /// For more information, see
 813        /// <see href="https://docs.microsoft.com/rest/api/storageservices/lease-container">
 814        /// Lease Container</see>.
 815        /// </summary>
 816        /// <param name="proposedId">
 817        /// An optional proposed lease ID, in a GUID string format. A
 818        /// <see cref="RequestFailedException"/> will be thrown if the
 819        /// proposed lease ID is not in the correct format.
 820        /// </param>
 821        /// <param name="conditions">
 822        /// Optional <see cref="BlobLeaseRequestConditions"/> to add
 823        /// conditions on changing a lease.
 824        /// </param>
 825        /// <param name="async">
 826        /// Whether to invoke the operation asynchronously.
 827        /// </param>
 828        /// <param name="cancellationToken">
 829        /// Optional <see cref="CancellationToken"/> to propagate
 830        /// notifications that the operation should be cancelled.
 831        /// </param>
 832        /// <returns>
 833        /// A <see cref="Response{Lease}"/> describing the lease.
 834        /// </returns>
 835        /// <remarks>
 836        /// A <see cref="RequestFailedException"/> will be thrown if
 837        /// a failure occurs.
 838        /// </remarks>
 839        private async Task<Response<BlobLease>> ChangeInternal(
 840            string proposedId,
 841            RequestConditions conditions,
 842            bool async,
 843            CancellationToken cancellationToken)
 844        {
 845            EnsureClient();
 846            using (Pipeline.BeginLoggingScope(nameof(BlobLeaseClient)))
 847            {
 848                Pipeline.LogMethodEnter(
 849                    nameof(BlobLeaseClient),
 850                    message:
 851                    $"{nameof(Uri)}: {Uri}\n" +
 852                    $"{nameof(LeaseId)}: {LeaseId}\n" +
 853                    $"{nameof(proposedId)}: {proposedId}\n" +
 854                    $"{nameof(conditions)}: {conditions}");
 855                try
 856                {
 857                    string tagCondition = null;
 858                    if (conditions != null && conditions.GetType() == typeof(BlobLeaseRequestConditions))
 859                    {
 860                        tagCondition = ((BlobLeaseRequestConditions)conditions).TagConditions;
 861                    }
 862
 863                    if (BlobClient != null)
 864                    {
 865                        return await BlobRestClient.Blob.ChangeLeaseAsync(
 866                            ClientDiagnostics,
 867                            Pipeline,
 868                            Uri,
 869                            leaseId: LeaseId,
 870                            proposedLeaseId: proposedId,
 871                            version: Version.ToVersionString(),
 872                            ifModifiedSince: conditions?.IfModifiedSince,
 873                            ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
 874                            ifMatch: conditions?.IfMatch,
 875                            ifNoneMatch: conditions?.IfNoneMatch,
 876                            ifTags: tagCondition,
 877                            async: async,
 878                            operationName: $"{nameof(BlobLeaseClient)}.{nameof(Change)}",
 879                            cancellationToken: cancellationToken)
 880                            .ConfigureAwait(false);
 881                    }
 882                    else
 883                    {
 884                        if (conditions?.IfMatch != default || conditions?.IfNoneMatch != default)
 885                        {
 886                            throw BlobErrors.BlobConditionsMustBeDefault(
 887                                nameof(conditions.IfMatch),
 888                                nameof(conditions.IfNoneMatch));
 889                        }
 890                        return await BlobRestClient.Container.ChangeLeaseAsync(
 891                            ClientDiagnostics,
 892                            Pipeline,
 893                            Uri,
 894                            leaseId: LeaseId,
 895                            proposedLeaseId: proposedId,
 896                            version: Version.ToVersionString(),
 897                            ifModifiedSince: conditions?.IfModifiedSince,
 898                            ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
 899                            async: async,
 900                            operationName: $"{nameof(BlobLeaseClient)}.{nameof(Change)}",
 901                            cancellationToken: cancellationToken)
 902                            .ConfigureAwait(false);
 903                    }
 904                }
 905                catch (Exception ex)
 906                {
 907                    Pipeline.LogException(ex);
 908                    throw;
 909                }
 910                finally
 911                {
 912                    Pipeline.LogMethodExit(nameof(BlobLeaseClient));
 913                }
 914            }
 915        }
 916        #endregion Change
 917
 918        #region Break
 919        /// <summary>
 920        /// The <see cref="Break"/> operation breaks the blob or
 921        /// container's previously-acquired lease (if it exists).
 922        ///
 923        /// Once a lease is broken, it cannot be renewed.  Any authorized
 924        /// request can break the lease; the request is not required to
 925        /// specify a matching lease ID.  When a lease is broken, the lease
 926        /// break <paramref name="breakPeriod"/> is allowed to elapse,
 927        /// during which time no lease operation except
 928        /// <see cref="Break(TimeSpan?, RequestConditions, CancellationToken)"/>
 929        /// and <see cref="Release"/> can be
 930        /// performed on the blob or container.  When a lease is successfully
 931        /// broken, the response indicates the interval in seconds until a new
 932        /// lease can be acquired.
 933        ///
 934        /// A lease that has been broken can also be released.  A client can
 935        /// immediately acquire a blob or container lease that has been
 936        /// released.
 937        ///
 938        /// For more information, see
 939        /// <see href="https://docs.microsoft.com/rest/api/storageservices/lease-container">
 940        /// Lease Container</see>.
 941        /// </summary>
 942        /// <param name="breakPeriod">
 943        /// Specifies the proposed duration the lease should continue before
 944        /// it is broken, in seconds, between 0 and 60.  This break period is
 945        /// only used if it is shorter than the time remaining on the lease.
 946        /// If longer, the time remaining on the lease is used.  A new lease
 947        /// will not be available before the break period has expired, but the
 948        /// lease may be held for longer than the break period.  If this value
 949        /// is not provided, a fixed-duration lease breaks after the remaining
 950        /// lease period elapses, and an infinite lease breaks immediately.
 951        /// </param>
 952        /// <param name="conditions">
 953        /// Optional <see cref="BlobLeaseRequestConditions"/> to add
 954        /// conditions on breaking a lease.
 955        /// </param>
 956        /// <param name="cancellationToken">
 957        /// Optional <see cref="CancellationToken"/> to propagate
 958        /// notifications that the operation should be cancelled.
 959        /// </param>
 960        /// <returns>
 961        /// A <see cref="Response{Lease}"/> describing the broken lease.
 962        /// </returns>
 963        /// <remarks>
 964        /// A <see cref="RequestFailedException"/> will be thrown if
 965        /// a failure occurs.
 966        /// </remarks>
 967        public virtual Response<BlobLease> Break(
 968            TimeSpan? breakPeriod = default,
 969            RequestConditions conditions = default,
 970            CancellationToken cancellationToken = default) =>
 971            BreakInternal(
 972                breakPeriod,
 973                conditions,
 974                false, // async
 975                cancellationToken)
 976                .EnsureCompleted();
 977
 978        /// <summary>
 979        /// The <see cref="BreakAsync"/> operation breaks the blob or
 980        /// container's previously-acquired lease (if it exists).
 981        ///
 982        /// Once a lease is broken, it cannot be renewed.  Any authorized
 983        /// request can break the lease; the request is not required to
 984        /// specify a matching lease ID.  When a lease is broken, the lease
 985        /// break <paramref name="breakPeriod"/> is allowed to elapse,
 986        /// during which time no lease operation except
 987        /// <see cref="BreakAsync(TimeSpan?, RequestConditions, CancellationToken)"/>
 988        /// and <see cref="ReleaseAsync"/> can be
 989        /// performed on the blob or container.  When a lease is successfully
 990        /// broken, the response indicates the interval in seconds until a new
 991        /// lease can be acquired.
 992        ///
 993        /// A lease that has been broken can also be released.  A client can
 994        /// immediately acquire a blob or container lease that has been
 995        /// released.
 996        ///
 997        /// For more information, see
 998        /// <see href="https://docs.microsoft.com/rest/api/storageservices/lease-container">
 999        /// Lease Container</see>.
 1000        /// </summary>
 1001        /// <param name="breakPeriod">
 1002        /// Specifies the proposed duration the lease should continue before
 1003        /// it is broken, in seconds, between 0 and 60.  This break period is
 1004        /// only used if it is shorter than the time remaining on the lease.
 1005        /// If longer, the time remaining on the lease is used.  A new lease
 1006        /// will not be available before the break period has expired, but the
 1007        /// lease may be held for longer than the break period.  If this value
 1008        /// is not provided, a fixed-duration lease breaks after the remaining
 1009        /// lease period elapses, and an infinite lease breaks immediately.
 1010        /// </param>
 1011        /// <param name="conditions">
 1012        /// Optional <see cref="BlobLeaseRequestConditions"/> to add
 1013        /// conditions on breaking a lease.
 1014        /// </param>
 1015        /// <param name="cancellationToken">
 1016        /// Optional <see cref="CancellationToken"/> to propagate
 1017        /// notifications that the operation should be cancelled.
 1018        /// </param>
 1019        /// <returns>
 1020        /// A <see cref="Response{Lease}"/> describing the broken lease.
 1021        /// </returns>
 1022        /// <remarks>
 1023        /// A <see cref="RequestFailedException"/> will be thrown if
 1024        /// a failure occurs.
 1025        /// </remarks>
 1026        public virtual async Task<Response<BlobLease>> BreakAsync(
 1027            TimeSpan? breakPeriod = default,
 1028            RequestConditions conditions = default,
 1029            CancellationToken cancellationToken = default) =>
 1030            await BreakInternal(
 1031                breakPeriod,
 1032                conditions,
 1033                true, // async
 1034                cancellationToken)
 1035                .ConfigureAwait(false);
 1036
 1037        /// <summary>
 1038        /// The <see cref="BreakInternal"/> operation breaks the blob or
 1039        /// container's previously-acquired lease (if it exists).
 1040        ///
 1041        /// Once a lease is broken, it cannot be renewed.  Any authorized
 1042        /// request can break the lease; the request is not required to
 1043        /// specify a matching lease ID.  When a lease is broken, the lease
 1044        /// break <paramref name="breakPeriod"/> is allowed to elapse,
 1045        /// during which time no lease operation except
 1046        /// <see cref="BreakAsync"/>
 1047        /// and <see cref="ReleaseAsync"/> can be
 1048        /// performed on the blob or container.  When a lease is successfully
 1049        /// broken, the response indicates the interval in seconds until a new
 1050        /// lease can be acquired.
 1051        ///
 1052        /// A lease that has been broken can also be released.  A client can
 1053        /// immediately acquire a blob or container lease that has been
 1054        /// released.
 1055        ///
 1056        /// For more information, see
 1057        /// <see href="https://docs.microsoft.com/rest/api/storageservices/lease-container">
 1058        /// Lease Container</see>.
 1059        /// </summary>
 1060        /// <param name="breakPeriod">
 1061        /// Specifies the proposed duration the lease should continue before
 1062        /// it is broken, in seconds, between 0 and 60.  This break period is
 1063        /// only used if it is shorter than the time remaining on the lease.
 1064        /// If longer, the time remaining on the lease is used.  A new lease
 1065        /// will not be available before the break period has expired, but the
 1066        /// lease may be held for longer than the break period.  If this value
 1067        /// is not provided, a fixed-duration lease breaks after the remaining
 1068        /// lease period elapses, and an infinite lease breaks immediately.
 1069        /// </param>
 1070        /// <param name="conditions">
 1071        /// Optional <see cref="BlobLeaseRequestConditions"/> to add
 1072        /// conditions on breaking a lease.
 1073        /// </param>
 1074        /// <param name="async">
 1075        /// Whether to invoke the operation asynchronously.
 1076        /// </param>
 1077        /// <param name="cancellationToken">
 1078        /// Optional <see cref="CancellationToken"/> to propagate
 1079        /// notifications that the operation should be cancelled.
 1080        /// </param>
 1081        /// <returns>
 1082        /// A <see cref="Response{Lease}"/> describing the broken lease.
 1083        /// </returns>
 1084        /// <remarks>
 1085        /// A <see cref="RequestFailedException"/> will be thrown if
 1086        /// a failure occurs.
 1087        /// </remarks>
 1088        private async Task<Response<BlobLease>> BreakInternal(
 1089            TimeSpan? breakPeriod,
 1090            RequestConditions conditions,
 1091            bool async,
 1092            CancellationToken cancellationToken)
 1093        {
 1094            EnsureClient();
 1095            long? serviceBreakPeriod = breakPeriod != null ? Convert.ToInt64(breakPeriod.Value.TotalSeconds) : (long?) n
 1096            using (Pipeline.BeginLoggingScope(nameof(BlobLeaseClient)))
 1097            {
 1098                Pipeline.LogMethodEnter(
 1099                    nameof(BlobLeaseClient),
 1100                    message:
 1101                    $"{nameof(Uri)}: {Uri}\n" +
 1102                    $"{nameof(breakPeriod)}: {breakPeriod}\n" +
 1103                    $"{nameof(conditions)}: {conditions}");
 1104                try
 1105                {
 1106                    string tagConditions = null;
 1107                    if (conditions != null && conditions.GetType() == typeof(BlobLeaseRequestConditions))
 1108                    {
 1109                        tagConditions = ((BlobLeaseRequestConditions)conditions).TagConditions;
 1110                    }
 1111
 1112                    if (BlobClient != null)
 1113                    {
 1114                        return (await BlobRestClient.Blob.BreakLeaseAsync(
 1115                            ClientDiagnostics,
 1116                            Pipeline,
 1117                            Uri,
 1118                            version: Version.ToVersionString(),
 1119                            breakPeriod: serviceBreakPeriod,
 1120                            ifModifiedSince: conditions?.IfModifiedSince,
 1121                            ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
 1122                            ifMatch: conditions?.IfMatch,
 1123                            ifNoneMatch: conditions?.IfNoneMatch,
 1124                            ifTags: tagConditions,
 1125                            async: async,
 1126                            operationName: $"{nameof(BlobLeaseClient)}.{nameof(Break)}",
 1127                            cancellationToken: cancellationToken)
 1128                            .ConfigureAwait(false))
 1129                            .ToLease();
 1130                    }
 1131                    else
 1132                    {
 1133                        if (conditions?.IfMatch != default || conditions?.IfNoneMatch != default)
 1134                        {
 1135                            throw BlobErrors.BlobConditionsMustBeDefault(
 1136                                nameof(conditions.IfMatch),
 1137                                nameof(conditions.IfNoneMatch));
 1138                        }
 1139                        return (await BlobRestClient.Container.BreakLeaseAsync(
 1140                            ClientDiagnostics,
 1141                            Pipeline,
 1142                            Uri,
 1143                            version: Version.ToVersionString(),
 1144                            breakPeriod: serviceBreakPeriod,
 1145                            ifModifiedSince: conditions?.IfModifiedSince,
 1146                            ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
 1147                            async: async,
 1148                            operationName: $"{nameof(BlobLeaseClient)}.{nameof(Break)}",
 1149                            cancellationToken: cancellationToken)
 1150                            .ConfigureAwait(false))
 1151                            .ToLease();
 1152                    }
 1153                }
 1154                catch (Exception ex)
 1155                {
 1156                    Pipeline.LogException(ex);
 1157                    throw;
 1158                }
 1159                finally
 1160                {
 1161                    Pipeline.LogMethodExit(nameof(BlobLeaseClient));
 1162                }
 1163            }
 1164        }
 1165        #endregion Break
 1166    }
 1167
 1168    /// <summary>
 1169    /// Add easy to discover methods to <see cref="BlobContainerClient"/> and
 1170    /// <see cref="BlobClient"/> for easily creating <see cref="BlobLeaseClient"/>
 1171    /// instances.
 1172    /// </summary>
 1173    public static partial class SpecializedBlobExtensions
 1174    {
 1175        /// <summary>
 1176        /// Initializes a new instance of the <see cref="BlobLeaseClient"/> class.
 1177        /// </summary>
 1178        /// <param name="client">
 1179        /// A <see cref="BlobClient"/> representing the blob being leased.
 1180        /// </param>
 1181        /// <param name="leaseId">
 1182        /// An optional lease ID.  If no lease ID is provided, a random lease
 1183        /// ID will be created.
 1184        /// </param>
 1185        public static BlobLeaseClient GetBlobLeaseClient(
 1186            this BlobBaseClient client,
 1187            string leaseId = null) =>
 4121188            new BlobLeaseClient(client, leaseId);
 1189
 1190        /// <summary>
 1191        /// Initializes a new instance of the <see cref="BlobLeaseClient"/> class.
 1192        /// </summary>
 1193        /// <param name="client">
 1194        /// A <see cref="BlobContainerClient"/> representing the container
 1195        /// being leased.
 1196        /// </param>
 1197        /// <param name="leaseId">
 1198        /// An optional lease ID.  If no lease ID is provided, a random lease
 1199        /// ID will be created.
 1200        /// </param>
 1201        public static BlobLeaseClient GetBlobLeaseClient(
 1202            this BlobContainerClient client,
 1203            string leaseId = null) =>
 2201204            new BlobLeaseClient(client, leaseId);
 1205    }
 1206}

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)]
 95        public virtual int BlockBlobMaxUploadBlobBytes => Version < BlobClientOptions.ServiceVersion.V2019_12_12
 96            ? Constants.Blob.Block.Pre_2019_12_12_MaxUploadBytes
 97            : 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>
 103        public virtual long BlockBlobMaxUploadBlobLongBytes => Version < BlobClientOptions.ServiceVersion.V2019_12_12
 104            ? Constants.Blob.Block.Pre_2019_12_12_MaxUploadBytes
 105            : 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)]
 114        public virtual int BlockBlobMaxStageBlockBytes => Version < BlobClientOptions.ServiceVersion.V2019_12_12
 115            ? Constants.Blob.Block.Pre_2019_12_12_MaxStageBytes
 116            : 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>
 122        public virtual long BlockBlobMaxStageBlockLongBytes => Version < BlobClientOptions.ServiceVersion.V2019_12_12
 123            ? Constants.Blob.Block.Pre_2019_12_12_MaxStageBytes
 124            : Constants.Blob.Block.MaxStageBytes;
 125
 126        /// <summary>
 127        /// Gets the maximum number of blocks allowed in a block blob.
 128        /// </summary>
 129        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>
 136        protected BlockBlobClient()
 137        {
 138        }
 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)
 160            : base(connectionString, containerName, blobName)
 161        {
 162        }
 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
 189            : base(connectionString, blobContainerName, blobName, options)
 190        {
 191            AssertNoClientSideEncryption(options);
 192        }
 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)
 209            : base(blobUri, options)
 210        {
 211            AssertNoClientSideEncryption(options);
 212        }
 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)
 232            : base(blobUri, credential, options)
 233        {
 234            AssertNoClientSideEncryption(options);
 235        }
 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)
 255            : base(blobUri, credential, options)
 256        {
 257            AssertNoClientSideEncryption(options);
 258        }
 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)
 285            : base(
 286                  blobUri,
 287                  pipeline,
 288                  version,
 289                  clientDiagnostics,
 290                  customerProvidedKey,
 291                  clientSideEncryption: default,
 292                  encryptionScope)
 293        {
 294        }
 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        {
 318            return new BlockBlobClient(blobUri, pipeline, options.Version, new ClientDiagnostics(options), null, null);
 319        }
 320
 321        private static void AssertNoClientSideEncryption(BlobClientOptions options)
 322        {
 323            if (options?._clientSideEncryptionOptions != default)
 324            {
 325                throw Errors.ClientSideEncryption.TypeNotSupported(typeof(BlockBlobClient));
 326            }
 327        }
 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>
 345        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        {
 361            var builder = new BlobUriBuilder(Uri) { VersionId = versionId };
 362            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        {
 374            var builder = new BlobUriBuilder(Uri) { Snapshot = snapshot };
 375
 376            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        {
 434            var uploader = GetPartitionedUploader(
 435                transferOptions: options?.TransferOptions ?? default,
 436                operationName: $"{nameof(BlockBlobClient)}.{nameof(Upload)}");
 437
 438            return uploader.UploadInternal(
 439                content,
 440                options,
 441                options.ProgressHandler,
 442                async: false,
 443                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        {
 484            var uploader = GetPartitionedUploader(
 485                transferOptions: options?.TransferOptions ?? default,
 486                operationName: $"{nameof(BlockBlobClient)}.{nameof(Upload)}");
 487
 488            return await uploader.UploadInternal(
 489                content,
 490                options,
 491                options.ProgressHandler,
 492                async: true,
 493                cancellationToken)
 494                .ConfigureAwait(false);
 495        }
 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)
 555            => Upload(
 556                content,
 557                new BlobUploadOptions
 558                {
 559                    HttpHeaders = httpHeaders,
 560                    Metadata = metadata,
 561                    Conditions = conditions,
 562                    AccessTier = accessTier,
 563                    ProgressHandler = progressHandler,
 564                },
 565                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)
 625            => await UploadAsync(
 626                content,
 627                new BlobUploadOptions
 628                {
 629                    HttpHeaders = httpHeaders,
 630                    Metadata = metadata,
 631                    Conditions = conditions,
 632                    AccessTier = accessTier,
 633                    ProgressHandler = progressHandler,
 634                },
 635                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        {
 707            content = content?.WithNoDispose().WithProgress(progressHandler);
 708            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                {
 718                    return await BlobRestClient.BlockBlob.UploadAsync(
 719                        ClientDiagnostics,
 720                        Pipeline,
 721                        Uri,
 722                        body: content,
 723                        contentLength: content?.Length ?? 0,
 724                        version: Version.ToVersionString(),
 725                        blobContentType: blobHttpHeaders?.ContentType,
 726                        blobContentEncoding: blobHttpHeaders?.ContentEncoding,
 727                        blobContentLanguage: blobHttpHeaders?.ContentLanguage,
 728                        blobContentHash: blobHttpHeaders?.ContentHash,
 729                        blobCacheControl: blobHttpHeaders?.CacheControl,
 730                        metadata: metadata,
 731                        leaseId: conditions?.LeaseId,
 732                        blobContentDisposition: blobHttpHeaders?.ContentDisposition,
 733                        encryptionKey: CustomerProvidedKey?.EncryptionKey,
 734                        encryptionKeySha256: CustomerProvidedKey?.EncryptionKeyHash,
 735                        encryptionAlgorithm: CustomerProvidedKey?.EncryptionAlgorithm,
 736                        encryptionScope: EncryptionScope,
 737                        tier: accessTier,
 738                        ifModifiedSince: conditions?.IfModifiedSince,
 739                        ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
 740                        ifMatch: conditions?.IfMatch,
 741                        ifNoneMatch: conditions?.IfNoneMatch,
 742                        ifTags: conditions?.TagConditions,
 743                        blobTagsString: tags?.ToTagsString(),
 744                        async: async,
 745                        operationName: operationName ?? $"{nameof(BlockBlobClient)}.{nameof(Upload)}",
 746                        cancellationToken: cancellationToken)
 747                        .ConfigureAwait(false);
 748                }
 749                catch (Exception ex)
 750                {
 751                    Pipeline.LogException(ex);
 752                    throw;
 753                }
 754                finally
 755                {
 756                    Pipeline.LogMethodExit(nameof(BlockBlobClient));
 757                }
 758            }
 759        }
 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) =>
 820            StageBlockInternal(
 821                base64BlockId,
 822                content,
 823                transactionalContentHash,
 824                conditions,
 825                progressHandler,
 826                false, // async
 827                cancellationToken)
 828                .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) =>
 887            await StageBlockInternal(
 888                base64BlockId,
 889                content,
 890                transactionalContentHash,
 891                conditions,
 892                progressHandler,
 893                true, // async
 894                cancellationToken)
 895                .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        {
 959            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                {
 969                    content = content.WithNoDispose().WithProgress(progressHandler);
 970                    return await BlobRestClient.BlockBlob.StageBlockAsync(
 971                        ClientDiagnostics,
 972                        Pipeline,
 973                        Uri,
 974                        blockId: base64BlockId,
 975                        body: content,
 976                        contentLength: content.Length,
 977                        version: Version.ToVersionString(),
 978                        transactionalContentHash: transactionalContentHash,
 979                        leaseId: conditions?.LeaseId,
 980                        encryptionKey: CustomerProvidedKey?.EncryptionKey,
 981                        encryptionKeySha256: CustomerProvidedKey?.EncryptionKeyHash,
 982                        encryptionAlgorithm: CustomerProvidedKey?.EncryptionAlgorithm,
 983                        encryptionScope: EncryptionScope,
 984                        async: async,
 985                        operationName: $"{nameof(BlockBlobClient)}.{nameof(StageBlock)}",
 986                        cancellationToken: cancellationToken).ConfigureAwait(false);
 987                }
 988                catch (Exception ex)
 989                {
 990                    Pipeline.LogException(ex);
 991                    throw;
 992                }
 993                finally
 994                {
 995                    Pipeline.LogMethodExit(nameof(BlockBlobClient));
 996                }
 997            }
 998        }
 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) =>
 1070            StageBlockFromUriInternal(
 1071                sourceUri,
 1072                base64BlockId,
 1073                sourceRange,
 1074                sourceContentHash,
 1075                sourceConditions,
 1076                conditions,
 1077                false, // async
 1078                cancellationToken)
 1079                .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) =>
 1149            await StageBlockFromUriInternal(
 1150                sourceUri,
 1151                base64BlockId,
 1152                sourceRange,
 1153                sourceContentHash,
 1154                sourceConditions,
 1155                conditions,
 1156                true, // async
 1157                cancellationToken)
 1158                .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        {
 1233            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                {
 1244                    return await BlobRestClient.BlockBlob.StageBlockFromUriAsync(
 1245                        ClientDiagnostics,
 1246                        Pipeline,
 1247                        Uri,
 1248                        contentLength: default,
 1249                        blockId: base64BlockId,
 1250                        sourceUri: sourceUri,
 1251                        version: Version.ToVersionString(),
 1252                        sourceRange: sourceRange.ToString(),
 1253                        sourceContentHash: sourceContentHash,
 1254                        encryptionKey: CustomerProvidedKey?.EncryptionKey,
 1255                        encryptionKeySha256: CustomerProvidedKey?.EncryptionKeyHash,
 1256                        encryptionAlgorithm: CustomerProvidedKey?.EncryptionAlgorithm,
 1257                        encryptionScope: EncryptionScope,
 1258                        leaseId: conditions?.LeaseId,
 1259                        sourceIfModifiedSince: sourceConditions?.IfModifiedSince,
 1260                        sourceIfUnmodifiedSince: sourceConditions?.IfUnmodifiedSince,
 1261                        sourceIfMatch: sourceConditions?.IfMatch,
 1262                        sourceIfNoneMatch: sourceConditions?.IfNoneMatch,
 1263                        async: async,
 1264                        operationName: $"{nameof(BlockBlobClient)}.{nameof(StageBlockFromUri)}",
 1265                        cancellationToken: cancellationToken)
 1266                        .ConfigureAwait(false);
 1267                }
 1268                catch (Exception ex)
 1269                {
 1270                    Pipeline.LogException(ex);
 1271                    throw;
 1272                }
 1273                finally
 1274                {
 1275                    Pipeline.LogMethodExit(nameof(BlockBlobClient));
 1276                }
 1277            }
 1278        }
 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) =>
 1326            CommitBlockListInternal(
 1327                base64BlockIds,
 1328                options?.HttpHeaders,
 1329                options?.Metadata,
 1330                options?.Tags,
 1331                options?.Conditions,
 1332                options?.AccessTier,
 1333                false, // async
 1334                cancellationToken)
 1335                .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) =>
 1397            CommitBlockListInternal(
 1398                base64BlockIds,
 1399                httpHeaders,
 1400                metadata,
 1401                default,
 1402                conditions,
 1403                accessTier,
 1404                false, // async
 1405                cancellationToken)
 1406                .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) =>
 1452            await CommitBlockListInternal(
 1453                base64BlockIds,
 1454                options?.HttpHeaders,
 1455                options?.Metadata,
 1456                options?.Tags,
 1457                options?.Conditions,
 1458                options?.AccessTier,
 1459                true, // async
 1460                cancellationToken)
 1461                .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) =>
 1523            await CommitBlockListInternal(
 1524                base64BlockIds,
 1525                httpHeaders,
 1526                metadata,
 1527                default,
 1528                conditions,
 1529                accessTier,
 1530                true, // async
 1531                cancellationToken)
 1532                .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        {
 1602            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                {
 1613                    var blocks = new BlockLookupList() { Latest = base64BlockIds.ToList() };
 1614                    return await BlobRestClient.BlockBlob.CommitBlockListAsync(
 1615                        ClientDiagnostics,
 1616                        Pipeline,
 1617                        Uri,
 1618                        blocks,
 1619                        version: Version.ToVersionString(),
 1620                        blobCacheControl: blobHttpHeaders?.CacheControl,
 1621                        blobContentType: blobHttpHeaders?.ContentType,
 1622                        blobContentEncoding: blobHttpHeaders?.ContentEncoding,
 1623                        blobContentLanguage: blobHttpHeaders?.ContentLanguage,
 1624                        blobContentHash: blobHttpHeaders?.ContentHash,
 1625                        metadata: metadata,
 1626                        leaseId: conditions?.LeaseId,
 1627                        blobContentDisposition: blobHttpHeaders?.ContentDisposition,
 1628                        encryptionKey: CustomerProvidedKey?.EncryptionKey,
 1629                        encryptionKeySha256: CustomerProvidedKey?.EncryptionKeyHash,
 1630                        encryptionAlgorithm: CustomerProvidedKey?.EncryptionAlgorithm,
 1631                        encryptionScope: EncryptionScope,
 1632                        tier: accessTier,
 1633                        ifModifiedSince: conditions?.IfModifiedSince,
 1634                        ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
 1635                        ifMatch: conditions?.IfMatch,
 1636                        ifNoneMatch: conditions?.IfNoneMatch,
 1637                        ifTags: conditions?.TagConditions,
 1638                        blobTagsString: tags?.ToTagsString(),
 1639                        async: async,
 1640                        operationName: $"{nameof(BlockBlobClient)}.{nameof(CommitBlockList)}",
 1641                        cancellationToken: cancellationToken)
 1642                        .ConfigureAwait(false);
 1643                }
 1644                catch (Exception ex)
 1645                {
 1646                    Pipeline.LogException(ex);
 1647                    throw;
 1648                }
 1649                finally
 1650                {
 1651                    Pipeline.LogMethodExit(nameof(BlockBlobClient));
 1652                }
 1653            }
 1654        }
 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) =>
 1701            GetBlockListInternal(
 1702                blockListTypes,
 1703                snapshot,
 1704                conditions,
 1705                false, // async
 1706                cancellationToken)
 1707                .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) =>
 1752            await GetBlockListInternal(
 1753                blockListTypes,
 1754                snapshot,
 1755                conditions,
 1756                true, // async
 1757                cancellationToken)
 1758                .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        {
 1808            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                {
 1819                    return (await BlobRestClient.BlockBlob.GetBlockListAsync(
 1820                        ClientDiagnostics,
 1821                        Pipeline,
 1822                        Uri,
 1823                        listType: blockListTypes.ToBlockListType(),
 1824                        version: Version.ToVersionString(),
 1825                        snapshot: snapshot,
 1826                        leaseId: conditions?.LeaseId,
 1827                        ifTags: conditions?.TagConditions,
 1828                        async: async,
 1829                        operationName: $"{nameof(BlockBlobClient)}.{nameof(GetBlockList)}",
 1830                        cancellationToken: cancellationToken)
 1831                        .ConfigureAwait(false))
 1832                        .ToBlockList();
 1833                }
 1834                catch (Exception ex)
 1835                {
 1836                    Pipeline.LogException(ex);
 1837                    throw;
 1838                }
 1839                finally
 1840                {
 1841                    Pipeline.LogMethodExit(nameof(BlockBlobClient));
 1842                }
 1843            }
 1844        }
 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) =>
 1877            QueryInternal(
 1878                querySqlExpression,
 1879                options,
 1880                async: false,
 1881                cancellationToken)
 1882            .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) =>
 1913            await QueryInternal(
 1914                querySqlExpression,
 1915                options,
 1916                async: true,
 1917                cancellationToken)
 1918            .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        {
 1954            using (Pipeline.BeginLoggingScope(nameof(BlockBlobClient)))
 1955            {
 1956                Pipeline.LogMethodEnter(nameof(BlockBlobClient), message: $"{nameof(Uri)}: {Uri}");
 1957
 1958                try
 1959                {
 1960                    QueryRequest queryRequest = new QueryRequest()
 1961                    {
 1962                        QueryType = Constants.QuickQuery.SqlQueryType,
 1963                        Expression = querySqlExpression,
 1964                        InputSerialization = options?.InputTextConfiguration.ToQuickQuerySerialization(),
 1965                        OutputSerialization = options?.OutputTextConfiguration.ToQuickQuerySerialization()
 1966                    };
 1967                    (Response<BlobQueryResult> result, Stream stream) = await BlobRestClient.Blob.QueryAsync(
 1968                        clientDiagnostics: ClientDiagnostics,
 1969                        pipeline: Pipeline,
 1970                        resourceUri: Uri,
 1971                        version: Version.ToVersionString(),
 1972                        queryRequest: queryRequest,
 1973                        leaseId: options?.Conditions?.LeaseId,
 1974                        encryptionKey: CustomerProvidedKey?.EncryptionKey,
 1975                        encryptionKeySha256: CustomerProvidedKey?.EncryptionKeyHash,
 1976                        encryptionAlgorithm: CustomerProvidedKey?.EncryptionAlgorithm,
 1977                        ifModifiedSince: options?.Conditions?.IfModifiedSince,
 1978                        ifUnmodifiedSince: options?.Conditions?.IfUnmodifiedSince,
 1979                        ifMatch: options?.Conditions?.IfMatch,
 1980                        ifNoneMatch: options?.Conditions?.IfNoneMatch,
 1981                        ifTags: options?.Conditions?.TagConditions,
 1982                        async: async,
 1983                        operationName: $"{nameof(BlockBlobClient)}.{nameof(Query)}",
 1984                        cancellationToken: cancellationToken)
 1985                        .ConfigureAwait(false);
 1986
 1987                    Action<BlobQueryError> errorHandler = options?._errorHandler;
 1988                    Stream parsedStream = new BlobQuickQueryStream(stream, options?.ProgressHandler, errorHandler);
 1989                    result.Value.Body = parsedStream;
 1990
 1991                    return Response.FromValue(result.Value.ToBlobDownloadInfo(), result.GetRawResponse());
 1992                }
 1993                catch (Exception ex)
 1994                {
 1995                    Pipeline.LogException(ex);
 1996                    throw;
 1997                }
 1998                finally
 1999                {
 2000                    Pipeline.LogMethodExit(nameof(BlockBlobClient));
 2001                }
 2002            }
 2003        }
 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)
 2011            =>  new PartitionedUploader<BlobUploadOptions, BlobContentInfo>(
 2012                GetPartitionedUploaderBehaviors(this),
 2013                transferOptions,
 2014                arrayPool,
 2015                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.
 2025                byte[] id = new byte[48]; // 48 raw bytes => 64 byte string once Base64 encoded
 2026                BitConverter.GetBytes(offset).CopyTo(id, 0);
 2027                return Convert.ToBase64String(id);
 2028            }
 2029
 2030            return new PartitionedUploader<BlobUploadOptions, BlobContentInfo>.Behaviors
 2031            {
 2032                SingleUpload = async (stream, args, progressHandler, operationName, async, cancellationToken)
 2033                    => await client.UploadInternal(
 2034                        stream,
 2035                        args.HttpHeaders,
 2036                        args.Metadata,
 2037                        args.Tags,
 2038                        args.Conditions,
 2039                        args.AccessTier,
 2040                        progressHandler,
 2041                        operationName,
 2042                        async,
 2043                        cancellationToken).ConfigureAwait(false),
 2044                UploadPartition = async (stream, offset, args, progressHandler, async, cancellationToken)
 2045                    => await client.StageBlockInternal(
 2046                        GenerateBlockId(offset),
 2047                        stream,
 2048                        transactionalContentHash: default,
 2049                        args.Conditions,
 2050                        progressHandler,
 2051                        async,
 2052                        cancellationToken).ConfigureAwait(false),
 2053                CommitPartitionedUpload = async (partitions, args, async, cancellationToken)
 2054                    => await client.CommitBlockListInternal(
 2055                        partitions.Select(partition => GenerateBlockId(partition.Offset)),
 2056                        args.HttpHeaders,
 2057                        args.Metadata,
 2058                        args.Tags,
 2059                        args.Conditions,
 2060                        args.AccessTier,
 2061                        async,
 2062                        cancellationToken).ConfigureAwait(false),
 2063                Scope = operationName => client.ClientDiagnostics.CreateScope(operationName
 2064                    ?? $"{nameof(Azure)}.{nameof(Storage)}.{nameof(Blobs)}.{nameof(BlobClient)}.{nameof(BlobClient.Uploa
 2065            };
 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        {
 21882092            if (client.ClientSideEncryption != default)
 2093            {
 02094                throw Errors.ClientSideEncryption.TypeNotSupported(typeof(BlockBlobClient));
 2095            }
 2096
 21882097            BlobUriBuilder blobUriBuilder = new BlobUriBuilder(client.Uri)
 21882098            {
 21882099                BlobName = blobName
 21882100            };
 2101
 21882102            return new BlockBlobClient(
 21882103                blobUriBuilder.ToUri(),
 21882104                client.Pipeline,
 21882105                client.Version,
 21882106                client.ClientDiagnostics,
 21882107                client.CustomerProvidedKey,
 21882108                client.EncryptionScope);
 2109        }
 2110    }
 2111}

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

#LineLine coverage
 1// Copyright (c) Microsoft Corporation. All rights reserved.
 2// Licensed under the MIT License.
 3
 4using System;
 5using System.ComponentModel;
 6using System.IO;
 7using System.Threading;
 8using System.Threading.Tasks;
 9using System.Xml.Serialization;
 10using Azure.Core;
 11using Azure.Core.Pipeline;
 12using Azure.Storage.Blobs.Models;
 13using Metadata = System.Collections.Generic.IDictionary<string, string>;
 14using Tags = System.Collections.Generic.IDictionary<string, string>;
 15
 16#pragma warning disable SA1402  // File may only contain a single type
 17
 18namespace Azure.Storage.Blobs.Specialized
 19{
 20    /// <summary>
 21    /// The <see cref="PageBlobClient"/> allows you to manipulate Azure
 22    /// Storage page blobs.
 23    ///
 24    /// Page blobs are a collection of 512-byte pages optimized for random
 25    /// read and write operations. To create a page blob, you initialize the
 26    /// page blob and specify the maximum size the page blob will grow. To add
 27    /// or update the contents of a page blob, you write a page or pages by
 28    /// specifying an offset and a range that align to 512-byte page
 29    /// boundaries.  A write to a page blob can overwrite just one page, some
 30    /// pages, or up to 4 MB of the page blob.  Writes to page blobs happen
 31    /// in-place and are immediately committed to the blob. The maximum size
 32    /// for a page blob is 8 TB.
 33    /// </summary>
 34    public class PageBlobClient : BlobBaseClient
 35    {
 36        /// <summary>
 37        /// Gets the number of bytes in a page (512).
 38        /// </summary>
 39    public virtual int PageBlobPageBytes => 512;
 40
 41        /// <summary>
 42        /// Gets the maximum number of bytes that can be sent in a call
 43        /// to the <see cref="UploadPagesAsync"/> operation.
 44        /// </summary>
 45        public virtual int PageBlobMaxUploadPagesBytes => 4 * Constants.MB; // 4MB
 46
 47        #region ctors
 48        /// <summary>
 49        /// Initializes a new instance of the <see cref="PageBlobClient"/>
 50        /// class for mocking.
 51        /// </summary>
 52        protected PageBlobClient()
 53        {
 54        }
 55
 56        /// <summary>
 57        /// Initializes a new instance of the <see cref="PageBlobClient"/>
 58        /// class.
 59        /// </summary>
 60        /// <param name="connectionString">
 61        /// A connection string includes the authentication information
 62        /// required for your application to access data in an Azure Storage
 63        /// account at runtime.
 64        ///
 65        /// For more information
 66        /// <see href="https://docs.microsoft.com/azure/storage/common/storage-configure-connection-string">
 67        /// Configure Azure Storage connection strings</see>
 68        /// </param>
 69        /// <param name="blobContainerName">
 70        /// The name of the container containing this page blob.
 71        /// </param>
 72        /// <param name="blobName">
 73        /// The name of this page blob.
 74        /// </param>
 75        public PageBlobClient(string connectionString, string blobContainerName, string blobName)
 76            : base(connectionString, blobContainerName, blobName)
 77        {
 78        }
 79
 80        /// <summary>
 81        /// Initializes a new instance of the <see cref="PageBlobClient"/>
 82        /// class.
 83        /// </summary>
 84        /// <param name="connectionString">
 85        /// A connection string includes the authentication information
 86        /// required for your application to access data in an Azure Storage
 87        /// account at runtime.
 88        ///
 89        /// For more information,
 90        /// <see href="https://docs.microsoft.com/azure/storage/common/storage-configure-connection-string">
 91        /// Configure Azure Storage connection strings</see>
 92        /// </param>
 93        /// <param name="blobContainerName">
 94        /// The name of the container containing this page blob.
 95        /// </param>
 96        /// <param name="blobName">
 97        /// The name of this page blob.
 98        /// </param>
 99        /// <param name="options">
 100        /// Optional client options that define the transport pipeline
 101        /// policies for authentication, retries, etc., that are applied to
 102        /// every request.
 103        /// </param>
 104        public PageBlobClient(string connectionString, string blobContainerName, string blobName, BlobClientOptions opti
 105            : base(connectionString, blobContainerName, blobName, options)
 106        {
 107            AssertNoClientSideEncryption(options);
 108        }
 109
 110        /// <summary>
 111        /// Initializes a new instance of the <see cref="PageBlobClient"/>
 112        /// class.
 113        /// </summary>
 114        /// <param name="blobUri">
 115        /// A <see cref="Uri"/> referencing the page blob that includes the
 116        /// name of the account, the name of the blob container, and the name of
 117        /// the blob.
 118        /// </param>
 119        /// <param name="options">
 120        /// Optional client options that define the transport pipeline
 121        /// policies for authentication, retries, etc., that are applied to
 122        /// every request.
 123        /// </param>
 124        public PageBlobClient(Uri blobUri, BlobClientOptions options = default)
 125            : base(blobUri, options)
 126        {
 127            AssertNoClientSideEncryption(options);
 128        }
 129
 130        /// <summary>
 131        /// Initializes a new instance of the <see cref="PageBlobClient"/>
 132        /// class.
 133        /// </summary>
 134        /// <param name="blobUri">
 135        /// A <see cref="Uri"/> referencing the page blob that includes the
 136        /// name of the account, the name of the blob container, and the name of
 137        /// the blob.
 138        /// </param>
 139        /// <param name="credential">
 140        /// The shared key credential used to sign requests.
 141        /// </param>
 142        /// <param name="options">
 143        /// Optional client options that define the transport pipeline
 144        /// policies for authentication, retries, etc., that are applied to
 145        /// every request.
 146        /// </param>
 147        public PageBlobClient(Uri blobUri, StorageSharedKeyCredential credential, BlobClientOptions options = default)
 148            : base(blobUri, credential, options)
 149        {
 150            AssertNoClientSideEncryption(options);
 151        }
 152
 153        /// <summary>
 154        /// Initializes a new instance of the <see cref="PageBlobClient"/>
 155        /// class.
 156        /// </summary>
 157        /// <param name="blobUri">
 158        /// A <see cref="Uri"/> referencing the page blob that includes the
 159        /// name of the account, the name of the blob container, and the name of
 160        /// the blob.
 161        /// </param>
 162        /// <param name="credential">
 163        /// The token credential used to sign requests.
 164        /// </param>
 165        /// <param name="options">
 166        /// Optional client options that define the transport pipeline
 167        /// policies for authentication, retries, etc., that are applied to
 168        /// every request.
 169        /// </param>
 170        public PageBlobClient(Uri blobUri, TokenCredential credential, BlobClientOptions options = default)
 171            : base(blobUri, credential, options)
 172        {
 173            AssertNoClientSideEncryption(options);
 174        }
 175
 176        /// <summary>
 177        /// Initializes a new instance of the <see cref="PageBlobClient"/>
 178        /// class.
 179        /// </summary>
 180        /// <param name="blobUri">
 181        /// A <see cref="Uri"/> referencing the page blob that includes the
 182        /// name of the account, the name of the blob container, and the name of
 183        /// the blob.
 184        /// </param>
 185        /// <param name="pipeline">
 186        /// The transport pipeline used to send every request.
 187        /// </param>
 188        /// <param name="version">
 189        /// The version of the service to use when sending requests.
 190        /// </param>
 191        /// <param name="clientDiagnostics">Client diagnostics.</param>
 192        /// <param name="customerProvidedKey">Customer provided key.</param>
 193        /// <param name="encryptionScope">Encryption scope.</param>
 194        internal PageBlobClient(
 195            Uri blobUri,
 196            HttpPipeline pipeline,
 197            BlobClientOptions.ServiceVersion version,
 198            ClientDiagnostics clientDiagnostics,
 199            CustomerProvidedKey? customerProvidedKey,
 200            string encryptionScope)
 201            : base(
 202                  blobUri,
 203                  pipeline,
 204                  version,
 205                  clientDiagnostics,
 206                  customerProvidedKey,
 207                  clientSideEncryption: default,
 208                  encryptionScope)
 209        {
 210        }
 211
 212        private static void AssertNoClientSideEncryption(BlobClientOptions options)
 213        {
 214            if (options?._clientSideEncryptionOptions != default)
 215            {
 216                throw Errors.ClientSideEncryption.TypeNotSupported(typeof(PageBlobClient));
 217            }
 218        }
 219        #endregion ctors
 220
 221        /// <summary>
 222        /// Initializes a new instance of the <see cref="PageBlobClient"/>
 223        /// class with an identical <see cref="Uri"/> source but the specified
 224        /// snapshot timestamp.
 225        ///
 226        /// For more information, see
 227        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/creating-a-snapshot-of-a-blob">
 228        /// Create a snapshot of a blob</see>.
 229        /// </summary>
 230        /// <param name="snapshot">The snapshot identifier.</param>
 231        /// <returns>A new <see cref="PageBlobClient"/> instance.</returns>
 232        /// <remarks>
 233        /// Pass null or empty string to remove the snapshot returning a URL
 234        /// to the base blob.
 235        /// </remarks>
 236        public new PageBlobClient WithSnapshot(string snapshot) => (PageBlobClient)WithSnapshotCore(snapshot);
 237
 238        /// <summary>
 239        /// Creates a new instance of the <see cref="PageBlobClient"/> class
 240        /// with an identical <see cref="Uri"/> source but the specified
 241        /// snapshot timestamp.
 242        /// </summary>
 243        /// <param name="snapshot">The snapshot identifier.</param>
 244        /// <returns>A new <see cref="PageBlobClient"/> instance.</returns>
 245        protected sealed override BlobBaseClient WithSnapshotCore(string snapshot)
 246        {
 247            var builder = new BlobUriBuilder(Uri)
 248            {
 249                Snapshot = snapshot
 250            };
 251
 252            return new PageBlobClient(
 253                builder.ToUri(),
 254                Pipeline,
 255                Version,
 256                ClientDiagnostics,
 257                CustomerProvidedKey,
 258                EncryptionScope);
 259        }
 260
 261        /// <summary>
 262        /// Creates a new PageBlobClient object identical to the source but with the specified version ID.
 263        /// Pass "" to remove the version ID returning a URL to the base blob.
 264        /// </summary>
 265        /// <param name="versionId">version ID</param>
 266        /// <returns></returns>
 267        public new PageBlobClient WithVersion(string versionId)
 268        {
 269            var builder = new BlobUriBuilder(Uri)
 270            {
 271                VersionId = versionId
 272            };
 273
 274            return new PageBlobClient(
 275                builder.ToUri(), Pipeline,
 276                Version,
 277                ClientDiagnostics,
 278                CustomerProvidedKey,
 279                EncryptionScope);
 280        }
 281
 282        #region Create
 283        /// <summary>
 284        /// The <see cref="Create(long, PageBlobCreateOptions, CancellationToken)"/>
 285        /// operation creates a new page blob of the specified <paramref name="size"/>.
 286        /// The content of any existing blob is overwritten with the newly initialized page blob
 287        /// To add content to the page blob, call the
 288        /// <see cref="UploadPages"/> operation.
 289        ///
 290        /// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-blob.
 291        /// </summary>
 292        /// <param name="size">
 293        /// Specifies the maximum size for the page blob, up to 8 TB.  The
 294        /// size must be aligned to a 512-byte boundary.
 295        /// </param>
 296        /// <param name="options">
 297        /// Optional parameters.
 298        /// </param>
 299        /// <param name="cancellationToken">
 300        /// Optional <see cref="CancellationToken"/> to propagate
 301        /// notifications that the operation should be cancelled.
 302        /// </param>
 303        /// <returns>
 304        /// A <see cref="Response{BlobContentInfo}"/> describing the
 305        /// newly created page blob.
 306        /// </returns>
 307        /// <remarks>
 308        /// A <see cref="RequestFailedException"/> will be thrown if
 309        /// a failure occurs.
 310        /// </remarks>
 311        public virtual Response<BlobContentInfo> Create(
 312            long size,
 313            PageBlobCreateOptions options,
 314            CancellationToken cancellationToken = default) =>
 315            CreateInternal(
 316                size,
 317                options?.SequenceNumber,
 318                options?.HttpHeaders,
 319                options?.Metadata,
 320                options?.Tags,
 321                options?.Conditions,
 322                async: false,
 323                cancellationToken)
 324            .EnsureCompleted();
 325
 326        /// <summary>
 327        /// The <see cref="CreateAsync(long, PageBlobCreateOptions, CancellationToken)"/>
 328        /// operation creates a new page blob of the specified <paramref name="size"/>.
 329        /// The content of any existing blob is overwritten with the newly initialized page blob
 330        /// To add content to the page blob, call the
 331        /// <see cref="UploadPages"/> operation.
 332        ///
 333        /// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-blob.
 334        /// </summary>
 335        /// <param name="size">
 336        /// Specifies the maximum size for the page blob, up to 8 TB.  The
 337        /// size must be aligned to a 512-byte boundary.
 338        /// </param>
 339        /// <param name="options">
 340        /// Optional parameters.
 341        /// </param>
 342        /// <param name="cancellationToken">
 343        /// Optional <see cref="CancellationToken"/> to propagate
 344        /// notifications that the operation should be cancelled.
 345        /// </param>
 346        /// <returns>
 347        /// A <see cref="Response{BlobContentInfo}"/> describing the
 348        /// newly created page blob.
 349        /// </returns>
 350        /// <remarks>
 351        /// A <see cref="RequestFailedException"/> will be thrown if
 352        /// a failure occurs.
 353        /// </remarks>
 354        public virtual async Task<Response<BlobContentInfo>> CreateAsync(
 355            long size,
 356            PageBlobCreateOptions options,
 357            CancellationToken cancellationToken = default) =>
 358            await CreateInternal(
 359                size,
 360                options?.SequenceNumber,
 361                options?.HttpHeaders,
 362                options?.Metadata,
 363                options?.Tags,
 364                options?.Conditions,
 365                async: true,
 366                cancellationToken)
 367            .ConfigureAwait(false);
 368
 369        /// <summary>
 370        /// The <see cref="Create(long, long?, BlobHttpHeaders, Metadata, PageBlobRequestConditions, CancellationToken)"
 371        /// operation creates a new page blob of the specified <paramref name="size"/>.  The content of any
 372        /// existing blob is overwritten with the newly initialized page blob
 373        /// To add content to the page blob, call the
 374        /// <see cref="UploadPages"/> operation.
 375        ///
 376        /// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-blob.
 377        /// </summary>
 378        /// <param name="size">
 379        /// Specifies the maximum size for the page blob, up to 8 TB.  The
 380        /// size must be aligned to a 512-byte boundary.
 381        /// </param>
 382        /// <param name="sequenceNumber">
 383        /// Optional user-controlled value that you can use to track requests.
 384        /// The value of the <paramref name="sequenceNumber"/> must be between
 385        /// 0 and 2^63 - 1.  The default value is 0.
 386        /// </param>
 387        /// <param name="httpHeaders">
 388        /// Optional standard HTTP header properties that can be set for the
 389        /// new page blob.
 390        /// </param>
 391        /// <param name="metadata">
 392        /// Optional custom metadata to set for this page blob.
 393        /// </param>
 394        /// <param name="conditions">
 395        /// Optional <see cref="PageBlobRequestConditions"/> to add
 396        /// conditions on the creation of this new page blob.
 397        /// </param>
 398        /// <param name="cancellationToken">
 399        /// Optional <see cref="CancellationToken"/> to propagate
 400        /// notifications that the operation should be cancelled.
 401        /// </param>
 402        /// <returns>
 403        /// A <see cref="Response{BlobContentInfo}"/> describing the
 404        /// newly created page blob.
 405        /// </returns>
 406        /// <remarks>
 407        /// A <see cref="RequestFailedException"/> will be thrown if
 408        /// a failure occurs.
 409        /// </remarks>
 410        [EditorBrowsable(EditorBrowsableState.Never)]
 411        public virtual Response<BlobContentInfo> Create(
 412            long size,
 413            long? sequenceNumber = default,
 414            BlobHttpHeaders httpHeaders = default,
 415            Metadata metadata = default,
 416            PageBlobRequestConditions conditions = default,
 417            CancellationToken cancellationToken = default) =>
 418            CreateInternal(
 419                size,
 420                sequenceNumber,
 421                httpHeaders,
 422                metadata,
 423                default,
 424                conditions,
 425                false, // async
 426                cancellationToken)
 427                .EnsureCompleted();
 428
 429        /// <summary>
 430        /// The <see cref="CreateAsync(long, long?, BlobHttpHeaders, Metadata, PageBlobRequestConditions, CancellationTo
 431        /// operation creates a new page blob of the specified <paramref name="size"/>.  The content of any
 432        /// existing blob is overwritten with the newly initialized page blob
 433        /// To add content to the page blob, call the
 434        /// <see cref="UploadPagesAsync"/> operation.
 435        ///
 436        /// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-blob.
 437        /// </summary>
 438        /// <param name="size">
 439        /// Specifies the maximum size for the page blob, up to 8 TB.  The
 440        /// size must be aligned to a 512-byte boundary.
 441        /// </param>
 442        /// <param name="sequenceNumber">
 443        /// Optional user-controlled value that you can use to track requests.
 444        /// The value of the <paramref name="sequenceNumber"/> must be between
 445        /// 0 and 2^63 - 1.  The default value is 0.
 446        /// </param>
 447        /// <param name="httpHeaders">
 448        /// Optional standard HTTP header properties that can be set for the
 449        /// new page blob.
 450        /// </param>
 451        /// <param name="metadata">
 452        /// Optional custom metadata to set for this page blob.
 453        /// </param>
 454        /// <param name="conditions">
 455        /// Optional <see cref="PageBlobRequestConditions"/> to add
 456        /// conditions on the creation of this new page blob.
 457        /// </param>
 458        /// <param name="cancellationToken">
 459        /// Optional <see cref="CancellationToken"/> to propagate
 460        /// notifications that the operation should be cancelled.
 461        /// </param>
 462        /// <returns>
 463        /// A <see cref="Response{BlobContentInfo}"/> describing the
 464        /// newly created page blob.
 465        /// </returns>
 466        /// <remarks>
 467        /// A <see cref="RequestFailedException"/> will be thrown if
 468        /// a failure occurs.
 469        /// </remarks>
 470        [EditorBrowsable(EditorBrowsableState.Never)]
 471        public virtual async Task<Response<BlobContentInfo>> CreateAsync(
 472            long size,
 473            long? sequenceNumber = default,
 474            BlobHttpHeaders httpHeaders = default,
 475            Metadata metadata = default,
 476            PageBlobRequestConditions conditions = default,
 477            CancellationToken cancellationToken = default) =>
 478            await CreateInternal(
 479                size,
 480                sequenceNumber,
 481                httpHeaders,
 482                metadata,
 483                default,
 484                conditions,
 485                true, // async
 486                cancellationToken)
 487                .ConfigureAwait(false);
 488
 489        /// <summary>
 490        /// The <see cref="CreateIfNotExists(long, PageBlobCreateOptions, CancellationToken)"/>
 491        /// operation creates a new page blob of the specified <paramref name="size"/>.  If the blob already
 492        /// exists, the content of the existing blob will remain unchanged. If the blob does not already exists,
 493        /// a new page blob with the specified <paramref name="size"/> will be created.
 494        /// <see cref="UploadPages"/> operation.
 495        ///
 496        /// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-blob.
 497        /// </summary>
 498        /// <param name="size">
 499        /// Specifies the maximum size for the page blob, up to 8 TB.  The
 500        /// size must be aligned to a 512-byte boundary.
 501        /// </param>
 502        /// <param name="options">
 503        /// Optional parameters.
 504        /// </param>
 505        /// /// <param name="cancellationToken">
 506        /// Optional <see cref="CancellationToken"/> to propagate
 507        /// notifications that the operation should be cancelled.
 508        /// </param>
 509        /// <returns>
 510        /// If the page blob does not already exist, A <see cref="Response{BlobContentInfo}"/>
 511        /// describing the newly created page blob. Otherwise, <c>null</c>.
 512        /// </returns>
 513        /// <remarks>
 514        /// A <see cref="RequestFailedException"/> will be thrown if
 515        /// a failure occurs.
 516        /// </remarks>
 517        public virtual Response<BlobContentInfo> CreateIfNotExists(
 518            long size,
 519            PageBlobCreateOptions options,
 520            CancellationToken cancellationToken = default) =>
 521            CreateIfNotExistsInternal(
 522                size,
 523                options?.SequenceNumber,
 524                options?.HttpHeaders,
 525                options?.Metadata,
 526                options?.Tags,
 527                false, // async
 528                cancellationToken)
 529                .EnsureCompleted();
 530
 531        /// <summary>
 532        /// The <see cref="CreateIfNotExistsAsync(long, PageBlobCreateOptions, CancellationToken)"/>
 533        /// operation creates a new page blob of the specified <paramref name="size"/>.  If the blob already
 534        /// exists, the content of the existing blob will remain unchanged. If the blob does not already exists,
 535        /// a new page blob with the specified <paramref name="size"/> will be created.
 536        /// <see cref="UploadPages"/> operation.
 537        ///
 538        /// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-blob.
 539        /// </summary>
 540        /// <param name="size">
 541        /// Specifies the maximum size for the page blob, up to 8 TB.  The
 542        /// size must be aligned to a 512-byte boundary.
 543        /// </param>
 544        /// <param name="options">
 545        /// Optional parameters.
 546        /// </param>
 547        /// /// <param name="cancellationToken">
 548        /// Optional <see cref="CancellationToken"/> to propagate
 549        /// notifications that the operation should be cancelled.
 550        /// </param>
 551        /// <returns>
 552        /// If the page blob does not already exist, A <see cref="Response{BlobContentInfo}"/>
 553        /// describing the newly created page blob. Otherwise, <c>null</c>.
 554        /// </returns>
 555        /// <remarks>
 556        /// A <see cref="RequestFailedException"/> will be thrown if
 557        /// a failure occurs.
 558        /// </remarks>
 559        public virtual async Task<Response<BlobContentInfo>> CreateIfNotExistsAsync(
 560            long size,
 561            PageBlobCreateOptions options,
 562            CancellationToken cancellationToken = default) =>
 563            await CreateIfNotExistsInternal(
 564                size,
 565                options?.SequenceNumber,
 566                options?.HttpHeaders,
 567                options?.Metadata,
 568                options?.Tags,
 569                true, // async
 570                cancellationToken)
 571                .ConfigureAwait(false);
 572
 573        /// <summary>
 574        /// The <see cref="CreateIfNotExists(long, long?, BlobHttpHeaders, Metadata, CancellationToken)"/>
 575        /// operation creates a new page blob of the specified <paramref name="size"/>.  If the blob already
 576        /// exists, the content of the existing blob will remain unchanged. If the blob does not already exists,
 577        /// a new page blob with the specified <paramref name="size"/> will be created.
 578        /// <see cref="UploadPages"/> operation.
 579        ///
 580        /// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-blob.
 581        /// </summary>
 582        /// <param name="size">
 583        /// Specifies the maximum size for the page blob, up to 8 TB.  The
 584        /// size must be aligned to a 512-byte boundary.
 585        /// </param>
 586        /// <param name="sequenceNumber">
 587        /// Optional user-controlled value that you can use to track requests.
 588        /// The value of the <paramref name="sequenceNumber"/> must be between
 589        /// 0 and 2^63 - 1.  The default value is 0.
 590        /// </param>
 591        /// <param name="httpHeaders">
 592        /// Optional standard HTTP header properties that can be set for the
 593        /// new page blob.
 594        /// </param>
 595        /// <param name="metadata">
 596        /// Optional custom metadata to set for this page blob.
 597        /// </param>
 598        /// /// <param name="cancellationToken">
 599        /// Optional <see cref="CancellationToken"/> to propagate
 600        /// notifications that the operation should be cancelled.
 601        /// </param>
 602        /// <returns>
 603        /// If the page blob does not already exist, A <see cref="Response{BlobContentInfo}"/>
 604        /// describing the newly created page blob. Otherwise, <c>null</c>.
 605        /// </returns>
 606        /// <remarks>
 607        /// A <see cref="RequestFailedException"/> will be thrown if
 608        /// a failure occurs.
 609        /// </remarks>
 610        [EditorBrowsable(EditorBrowsableState.Never)]
 611        public virtual Response<BlobContentInfo> CreateIfNotExists(
 612            long size,
 613            long? sequenceNumber = default,
 614            BlobHttpHeaders httpHeaders = default,
 615            Metadata metadata = default,
 616            CancellationToken cancellationToken = default) =>
 617            CreateIfNotExistsInternal(
 618                size,
 619                sequenceNumber,
 620                httpHeaders,
 621                metadata,
 622                default,
 623                false, // async
 624                cancellationToken)
 625                .EnsureCompleted();
 626
 627        /// <summary>
 628        /// The <see cref="CreateIfNotExistsAsync(long, long?, BlobHttpHeaders, Metadata, CancellationToken)"/>
 629        /// operation creates a new page blob of the specified <paramref name="size"/>.  If the blob already exists,
 630        /// the content of the existing blob will remain unchanged. If the blob does not already exists,
 631        /// a new page blob with the specified <paramref name="size"/> will be created.
 632        /// <see cref="UploadPagesAsync"/> operation.
 633        ///
 634        /// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-blob.
 635        /// </summary>
 636        /// <param name="size">
 637        /// Specifies the maximum size for the page blob, up to 8 TB.  The
 638        /// size must be aligned to a 512-byte boundary.
 639        /// </param>
 640        /// <param name="sequenceNumber">
 641        /// Optional user-controlled value that you can use to track requests.
 642        /// The value of the <paramref name="sequenceNumber"/> must be between
 643        /// 0 and 2^63 - 1.  The default value is 0.
 644        /// </param>
 645        /// <param name="httpHeaders">
 646        /// Optional standard HTTP header properties that can be set for the
 647        /// new page blob.
 648        /// </param>
 649        /// <param name="metadata">
 650        /// Optional custom metadata to set for this page blob.
 651        /// </param>
 652        /// <param name="cancellationToken">
 653        /// Optional <see cref="CancellationToken"/> to propagate
 654        /// notifications that the operation should be cancelled.
 655        /// </param>
 656        /// <returns>
 657        /// If the page blob does not already exist, A <see cref="Response{BlobContentInfo}"/>
 658        /// describing the newly created page blob. Otherwise, <c>null</c>.
 659        /// </returns>
 660        /// <remarks>
 661        /// A <see cref="RequestFailedException"/> will be thrown if
 662        /// a failure occurs.
 663        /// </remarks>
 664        [EditorBrowsable(EditorBrowsableState.Never)]
 665        public virtual async Task<Response<BlobContentInfo>> CreateIfNotExistsAsync(
 666            long size,
 667            long? sequenceNumber = default,
 668            BlobHttpHeaders httpHeaders = default,
 669            Metadata metadata = default,
 670            CancellationToken cancellationToken = default) =>
 671            await CreateIfNotExistsInternal(
 672                size,
 673                sequenceNumber,
 674                httpHeaders,
 675                metadata,
 676                default,
 677                true, // async
 678                cancellationToken)
 679                .ConfigureAwait(false);
 680
 681        /// <summary>
 682        /// The <see cref="CreateIfNotExistsInternal"/> operation creates a new page blob
 683        /// of the specified <paramref name="size"/>.  If the blob already exists, the content of
 684        /// the existing blob will remain unchanged. If the blob does not already exists,
 685        /// a new page blob with the specified <paramref name="size"/> will be created.
 686        /// To add content to the page blob, call the
 687        /// <see cref="UploadPagesAsync"/> operation.
 688        ///
 689        /// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-blob.
 690        /// </summary>
 691        /// <param name="size">
 692        /// Specifies the maximum size for the page blob, up to 8 TB.  The
 693        /// size must be aligned to a 512-byte boundary.
 694        /// </param>
 695        /// <param name="sequenceNumber">
 696        /// Optional user-controlled value that you can use to track requests.
 697        /// The value of the <paramref name="sequenceNumber"/> must be between
 698        /// 0 and 2^63 - 1.  The default value is 0.
 699        /// </param>
 700        /// <param name="httpHeaders">
 701        /// Optional standard HTTP header properties that can be set for the
 702        /// new page blob.
 703        /// </param>
 704        /// <param name="metadata">
 705        /// Optional custom metadata to set for this page blob.
 706        /// </param>
 707        /// <param name="tags">
 708        /// Optional tags to set for this page blob.
 709        /// </param>
 710        /// <param name="async">
 711        /// Whether to invoke the operation asynchronously.
 712        /// </param>
 713        /// <param name="cancellationToken">
 714        /// Optional <see cref="CancellationToken"/> to propagate
 715        /// notifications that the operation should be cancelled.
 716        /// </param>
 717        /// <returns>
 718        /// If the page blob does not already exist, A <see cref="Response{BlobContentInfo}"/>
 719        /// describing the newly created page blob. Otherwise, <c>null</c>.
 720        /// </returns>
 721        /// <remarks>
 722        /// A <see cref="RequestFailedException"/> will be thrown if
 723        /// a failure occurs.
 724        /// </remarks>
 725        private async Task<Response<BlobContentInfo>> CreateIfNotExistsInternal(
 726            long size,
 727            long? sequenceNumber,
 728            BlobHttpHeaders httpHeaders,
 729            Metadata metadata,
 730            Tags tags,
 731            bool async,
 732            CancellationToken cancellationToken)
 733        {
 734            using (Pipeline.BeginLoggingScope(nameof(PageBlobClient)))
 735            {
 736                Pipeline.LogMethodEnter(
 737                    nameof(PageBlobClient),
 738                    message:
 739                    $"{nameof(Uri)}: {Uri}\n" +
 740                    $"{nameof(size)}: {size}\n" +
 741                    $"{nameof(sequenceNumber)}: {sequenceNumber}\n" +
 742                    $"{nameof(httpHeaders)}: {httpHeaders}");
 743                var conditions = new PageBlobRequestConditions { IfNoneMatch = new ETag(Constants.Wildcard) };
 744                try
 745                {
 746                    return await CreateInternal(
 747                        size,
 748                        sequenceNumber,
 749                        httpHeaders,
 750                        metadata,
 751                        tags,
 752                        conditions,
 753                        async,
 754                        cancellationToken,
 755                        $"{nameof(PageBlobClient)}.{nameof(CreateIfNotExists)}")
 756                        .ConfigureAwait(false);
 757                }
 758                catch (RequestFailedException storageRequestFailedException)
 759                when (storageRequestFailedException.ErrorCode == BlobErrorCode.BlobAlreadyExists)
 760                {
 761                    return default;
 762                }
 763                catch (Exception ex)
 764                {
 765                    Pipeline.LogException(ex);
 766                    throw;
 767                }
 768                finally
 769                {
 770                    Pipeline.LogMethodExit(nameof(PageBlobClient));
 771                }
 772            }
 773        }
 774
 775        /// <summary>
 776        /// The <see cref="CreateInternal"/> operation creates a new page blob
 777        /// of the specified <paramref name="size"/>.  The content of any
 778        /// existing blob is overwritten with the newly initialized page blob
 779        /// To add content to the page blob, call the
 780        /// <see cref="UploadPagesAsync"/> operation.
 781        ///
 782        /// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-blob.
 783        /// </summary>
 784        /// <param name="size">
 785        /// Specifies the maximum size for the page blob, up to 8 TB.  The
 786        /// size must be aligned to a 512-byte boundary.
 787        /// </param>
 788        /// <param name="sequenceNumber">
 789        /// Optional user-controlled value that you can use to track requests.
 790        /// The value of the <paramref name="sequenceNumber"/> must be between
 791        /// 0 and 2^63 - 1.  The default value is 0.
 792        /// </param>
 793        /// <param name="httpHeaders">
 794        /// Optional standard HTTP header properties that can be set for the
 795        /// new page blob.
 796        /// </param>
 797        /// <param name="metadata">
 798        /// Optional custom metadata to set for this page blob.
 799        /// </param>
 800        /// <param name="tags">
 801        /// Optional tags to set for this page blob.
 802        /// </param>
 803        /// <param name="conditions">
 804        /// Optional <see cref="PageBlobRequestConditions"/> to add
 805        /// conditions on the creation of this new page blob.
 806        /// </param>
 807        /// <param name="async">
 808        /// Whether to invoke the operation asynchronously.
 809        /// </param>
 810        /// <param name="cancellationToken">
 811        /// Optional <see cref="CancellationToken"/> to propagate
 812        /// notifications that the operation should be cancelled.
 813        /// </param>
 814        /// <param name="operationName">
 815        /// Optional. To indicate if the name of the operation.
 816        /// </param>
 817        /// <returns>
 818        /// A <see cref="Response{BlobContentInfo}"/> describing the
 819        /// newly created page blob.
 820        /// </returns>
 821        /// <remarks>
 822        /// A <see cref="RequestFailedException"/> will be thrown if
 823        /// a failure occurs.
 824        /// </remarks>
 825        private async Task<Response<BlobContentInfo>> CreateInternal(
 826            long size,
 827            long? sequenceNumber,
 828            BlobHttpHeaders httpHeaders,
 829            Metadata metadata,
 830            Tags tags,
 831            PageBlobRequestConditions conditions,
 832            bool async,
 833            CancellationToken cancellationToken,
 834            string operationName = null)
 835        {
 836            using (Pipeline.BeginLoggingScope(nameof(PageBlobClient)))
 837            {
 838                Pipeline.LogMethodEnter(
 839                    nameof(PageBlobClient),
 840                    message:
 841                    $"{nameof(Uri)}: {Uri}\n" +
 842                    $"{nameof(size)}: {size}\n" +
 843                    $"{nameof(sequenceNumber)}: {sequenceNumber}\n" +
 844                    $"{nameof(httpHeaders)}: {httpHeaders}");
 845                try
 846                {
 847                    return await BlobRestClient.PageBlob.CreateAsync(
 848                        ClientDiagnostics,
 849                        Pipeline,
 850                        Uri,
 851                        version: Version.ToVersionString(),
 852                        contentLength: default,
 853                        blobContentType: httpHeaders?.ContentType,
 854                        blobContentEncoding: httpHeaders?.ContentEncoding,
 855                        blobContentLanguage: httpHeaders?.ContentLanguage,
 856                        blobContentHash: httpHeaders?.ContentHash,
 857                        blobCacheControl: httpHeaders?.CacheControl,
 858                        metadata: metadata,
 859                        leaseId: conditions?.LeaseId,
 860                        encryptionKey: CustomerProvidedKey?.EncryptionKey,
 861                        encryptionKeySha256: CustomerProvidedKey?.EncryptionKeyHash,
 862                        encryptionAlgorithm: CustomerProvidedKey?.EncryptionAlgorithm,
 863                        encryptionScope: EncryptionScope,
 864                        blobContentDisposition: httpHeaders?.ContentDisposition,
 865                        ifModifiedSince: conditions?.IfModifiedSince,
 866                        ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
 867                        ifMatch: conditions?.IfMatch,
 868                        ifNoneMatch: conditions?.IfNoneMatch,
 869                        ifTags: conditions?.TagConditions,
 870                        blobContentLength: size,
 871                        blobSequenceNumber: sequenceNumber,
 872                        blobTagsString: tags?.ToTagsString(),
 873                        async: async,
 874                        operationName: operationName ?? $"{nameof(PageBlobClient)}.{nameof(Create)}",
 875                        cancellationToken: cancellationToken)
 876                        .ConfigureAwait(false);
 877                }
 878                catch (Exception ex)
 879                {
 880                    Pipeline.LogException(ex);
 881                    throw;
 882                }
 883                finally
 884                {
 885                    Pipeline.LogMethodExit(nameof(PageBlobClient));
 886                }
 887            }
 888        }
 889        #endregion Create
 890
 891        #region UploadPages
 892        /// <summary>
 893        /// The <see cref="UploadPages"/> operation writes
 894        /// <paramref name="content"/> to a range of pages in a page blob,
 895        /// starting at <paramref name="offset"/>.
 896        ///
 897        /// For more information, see
 898        /// <see href="https://docs.microsoft.com/rest/api/storageservices/put-page">
 899        /// Put Page</see>.
 900        /// </summary>
 901        /// <param name="content">
 902        /// A <see cref="Stream"/> containing the content of the pages to
 903        /// upload.  The content can be up to 4 MB in size.
 904        /// </param>
 905        /// <param name="offset">
 906        /// Specifies the starting offset for the <paramref name="content"/>
 907        /// to be written as a page.  Given that pages must be aligned with
 908        /// 512-byte boundaries, the start offset must be a modulus of 512.
 909        /// </param>
 910        /// <param name="transactionalContentHash">
 911        /// Optional MD5 hash of the block content.  This hash is used to
 912        /// verify the integrity of the block during transport. When this hash
 913        /// is specified, the storage service compares the hash of the content
 914        /// that has arrived with this value.  Note that this MD5 hash is not
 915        /// stored with the blob.  If the two hashes do not match, the
 916        /// operation will fail with a <see cref="RequestFailedException"/>.
 917        /// </param>
 918        /// <param name="conditions">
 919        /// Optional <see cref="PageBlobRequestConditions"/> to add
 920        /// conditions on uploading pages to this page blob.
 921        /// </param>
 922        /// <param name="progressHandler">
 923        /// Optional <see cref="IProgress{Long}"/> to provide
 924        /// progress updates about data transfers.
 925        /// </param>
 926        /// <param name="cancellationToken">
 927        /// Optional <see cref="CancellationToken"/> to propagate
 928        /// notifications that the operation should be cancelled.
 929        /// </param>
 930        /// <returns>
 931        /// A <see cref="Response{PageInfo}"/> describing the
 932        /// state of the updated pages.
 933        /// </returns>
 934        /// <remarks>
 935        /// A <see cref="RequestFailedException"/> will be thrown if
 936        /// a failure occurs.
 937        /// </remarks>
 938        public virtual Response<PageInfo> UploadPages(
 939            Stream content,
 940            long offset,
 941            byte[] transactionalContentHash = default,
 942            PageBlobRequestConditions conditions = default,
 943            IProgress<long> progressHandler = default,
 944            CancellationToken cancellationToken = default) =>
 945            UploadPagesInternal(
 946                content,
 947                offset,
 948                transactionalContentHash,
 949                conditions,
 950                progressHandler,
 951                false, // async
 952                cancellationToken)
 953                .EnsureCompleted();
 954
 955        /// <summary>
 956        /// The <see cref="UploadPagesAsync"/> operation writes
 957        /// <paramref name="content"/> to a range of pages in a page blob,
 958        /// starting at <paramref name="offset"/>.
 959        ///
 960        /// For more information, see
 961        /// <see href="https://docs.microsoft.com/rest/api/storageservices/put-page">
 962        /// Put Page</see>.
 963        /// </summary>
 964        /// <param name="content">
 965        /// A <see cref="Stream"/> containing the content of the pages to
 966        /// upload.  The content can be up to 4 MB in size.
 967        /// </param>
 968        /// <param name="offset">
 969        /// Specifies the starting offset for the <paramref name="content"/>
 970        /// to be written as a page.  Given that pages must be aligned with
 971        /// 512-byte boundaries, the start offset must be a modulus of 512.
 972        /// </param>
 973        /// <param name="transactionalContentHash">
 974        /// Optional MD5 hash of the block content.  This hash is used to
 975        /// verify the integrity of the block during transport. When this hash
 976        /// is specified, the storage service compares the hash of the content
 977        /// that has arrived with this value.  Note that this MD5 hash is not
 978        /// stored with the blob.  If the two hashes do not match, the
 979        /// operation will fail with a <see cref="RequestFailedException"/>.
 980        /// </param>
 981        /// <param name="conditions">
 982        /// Optional <see cref="PageBlobRequestConditions"/> to add
 983        /// conditions on uploading pages to this page blob.
 984        /// </param>
 985        /// <param name="progressHandler">
 986        /// Optional <see cref="IProgress{Long}"/> to provide
 987        /// progress updates about data transfers.
 988        /// </param>
 989        /// <param name="cancellationToken">
 990        /// Optional <see cref="CancellationToken"/> to propagate
 991        /// notifications that the operation should be cancelled.
 992        /// </param>
 993        /// <returns>
 994        /// A <see cref="Response{PageInfo}"/> describing the
 995        /// state of the updated pages.
 996        /// </returns>
 997        /// <remarks>
 998        /// A <see cref="RequestFailedException"/> will be thrown if
 999        /// a failure occurs.
 1000        /// </remarks>
 1001        public virtual async Task<Response<PageInfo>> UploadPagesAsync(
 1002            Stream content,
 1003            long offset,
 1004            byte[] transactionalContentHash = default,
 1005            PageBlobRequestConditions conditions = default,
 1006            IProgress<long> progressHandler = default,
 1007            CancellationToken cancellationToken = default) =>
 1008            await UploadPagesInternal(
 1009                content,
 1010                offset,
 1011                transactionalContentHash,
 1012                conditions,
 1013                progressHandler,
 1014                true, // async
 1015                cancellationToken)
 1016                .ConfigureAwait(false);
 1017
 1018        /// <summary>
 1019        /// The <see cref="UploadPagesInternal"/> operation writes
 1020        /// <paramref name="content"/> to a range of pages in a page blob,
 1021        /// starting at <paramref name="offset"/>.
 1022        ///
 1023        /// For more information, see
 1024        /// <see href="https://docs.microsoft.com/rest/api/storageservices/put-page">
 1025        /// Put Page</see>.
 1026        /// </summary>
 1027        /// <param name="content">
 1028        /// A <see cref="Stream"/> containing the content of the pages to
 1029        /// upload.  The content can be up to 4 MB in size.
 1030        /// </param>
 1031        /// <param name="offset">
 1032        /// Specifies the starting offset for the <paramref name="content"/>
 1033        /// to be written as a page.  Given that pages must be aligned with
 1034        /// 512-byte boundaries, the start offset must be a modulus of 512.
 1035        /// </param>
 1036        /// <param name="transactionalContentHash">
 1037        /// Optional MD5 hash of the block content.  This hash is used to
 1038        /// verify the integrity of the block during transport. When this hash
 1039        /// is specified, the storage service compares the hash of the content
 1040        /// that has arrived with this value.  Note that this MD5 hash is not
 1041        /// stored with the blob.  If the two hashes do not match, the
 1042        /// operation will fail with a <see cref="RequestFailedException"/>.
 1043        /// </param>
 1044        /// <param name="conditions">
 1045        /// Optional <see cref="PageBlobRequestConditions"/> to add
 1046        /// conditions on uploading pages to this page blob.
 1047        /// </param>
 1048        /// <param name="progressHandler">
 1049        /// Optional <see cref="IProgress{Long}"/> to provide
 1050        /// progress updates about data transfers.
 1051        /// </param>
 1052        /// <param name="async">
 1053        /// Whether to invoke the operation asynchronously.
 1054        /// </param>
 1055        /// <param name="cancellationToken">
 1056        /// Optional <see cref="CancellationToken"/> to propagate
 1057        /// notifications that the operation should be cancelled.
 1058        /// </param>
 1059        /// <returns>
 1060        /// A <see cref="Response{PageInfo}"/> describing the
 1061        /// state of the updated pages.
 1062        /// </returns>
 1063        /// <remarks>
 1064        /// A <see cref="RequestFailedException"/> will be thrown if
 1065        /// a failure occurs.
 1066        /// </remarks>
 1067        private async Task<Response<PageInfo>> UploadPagesInternal(
 1068            Stream content,
 1069            long offset,
 1070            byte[] transactionalContentHash,
 1071            PageBlobRequestConditions conditions,
 1072            IProgress<long> progressHandler,
 1073            bool async,
 1074            CancellationToken cancellationToken)
 1075        {
 1076            using (Pipeline.BeginLoggingScope(nameof(PageBlobClient)))
 1077            {
 1078                Pipeline.LogMethodEnter(
 1079                    nameof(PageBlobClient),
 1080                    message:
 1081                    $"{nameof(Uri)}: {Uri}\n" +
 1082                    $"{nameof(offset)}: {offset}\n" +
 1083                    $"{nameof(conditions)}: {conditions}");
 1084                try
 1085                {
 1086                    content = content?.WithNoDispose().WithProgress(progressHandler);
 1087                    var range = new HttpRange(offset, content?.Length ?? null);
 1088
 1089                    return await BlobRestClient.PageBlob.UploadPagesAsync(
 1090                        ClientDiagnostics,
 1091                        Pipeline,
 1092                        Uri,
 1093                        body: content,
 1094                        contentLength: content?.Length ?? 0,
 1095                        version: Version.ToVersionString(),
 1096                        transactionalContentHash: transactionalContentHash,
 1097                        timeout: default,
 1098                        range: range.ToString(),
 1099                        leaseId: conditions?.LeaseId,
 1100                        encryptionKey: CustomerProvidedKey?.EncryptionKey,
 1101                        encryptionKeySha256: CustomerProvidedKey?.EncryptionKeyHash,
 1102                        encryptionAlgorithm: CustomerProvidedKey?.EncryptionAlgorithm,
 1103                        encryptionScope: EncryptionScope,
 1104                        ifSequenceNumberLessThanOrEqualTo: conditions?.IfSequenceNumberLessThanOrEqual,
 1105                        ifSequenceNumberLessThan: conditions?.IfSequenceNumberLessThan,
 1106                        ifSequenceNumberEqualTo: conditions?.IfSequenceNumberEqual,
 1107                        ifModifiedSince: conditions?.IfModifiedSince,
 1108                        ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
 1109                        ifMatch: conditions?.IfMatch,
 1110                        ifNoneMatch: conditions?.IfNoneMatch,
 1111                        ifTags: conditions?.TagConditions,
 1112                        async: async,
 1113                        operationName: $"{nameof(PageBlobClient)}.{nameof(UploadPages)}",
 1114                        cancellationToken: cancellationToken).ConfigureAwait(false);
 1115                }
 1116                catch (Exception ex)
 1117                {
 1118                    Pipeline.LogException(ex);
 1119                    throw;
 1120                }
 1121                finally
 1122                {
 1123                    Pipeline.LogMethodExit(nameof(PageBlobClient));
 1124                }
 1125            }
 1126        }
 1127        #endregion UploadPages
 1128
 1129        #region ClearPages
 1130        /// <summary>
 1131        /// The <see cref="ClearPages"/> operation clears one or more
 1132        /// pages from the page blob, as specificed by the <paramref name="range"/>.
 1133        ///
 1134        /// For more information, see
 1135        /// <see href="https://docs.microsoft.com/rest/api/storageservices/put-page">
 1136        /// Put Page</see>.
 1137        /// </summary>
 1138        /// <param name="range">
 1139        /// Specifies the range of bytes to be cleared. Both the start and
 1140        /// end of the range must be specified.  For a page clear operation,
 1141        /// the page range can be up to the value of the blob's full size.
 1142        /// Given that pages must be aligned with 512-byte boundaries, the
 1143        /// start of the range must be a modulus of 512 and the end of the
 1144        /// range must be a modulus of 512 – 1.  Examples of valid byte ranges
 1145        /// are 0-511, 512-1023, etc.
 1146        /// </param>
 1147        /// <param name="conditions">
 1148        /// Optional <see cref="PageBlobRequestConditions"/> to add
 1149        /// conditions on clearing pages from this page blob.
 1150        /// </param>
 1151        /// <param name="cancellationToken">
 1152        /// Optional <see cref="CancellationToken"/> to propagate
 1153        /// notifications that the operation should be cancelled.
 1154        /// </param>
 1155        /// <returns>
 1156        /// A <see cref="Response{PageInfo}"/> describing the
 1157        /// state of the updated pages.
 1158        /// </returns>
 1159        /// <remarks>
 1160        /// A <see cref="RequestFailedException"/> will be thrown if
 1161        /// a failure occurs.
 1162        /// </remarks>
 1163        public virtual Response<PageInfo> ClearPages(
 1164            HttpRange range,
 1165            PageBlobRequestConditions conditions = default,
 1166            CancellationToken cancellationToken = default) =>
 1167            ClearPagesInternal(
 1168                range,
 1169                conditions,
 1170                false, // async
 1171                cancellationToken)
 1172                .EnsureCompleted();
 1173
 1174        /// <summary>
 1175        /// The <see cref="ClearPagesAsync"/> operation clears one or more
 1176        /// pages from the page blob, as specificed by the <paramref name="range"/>.
 1177        ///
 1178        /// For more information, see
 1179        /// <see href="https://docs.microsoft.com/rest/api/storageservices/put-page">
 1180        /// Put Page</see>.
 1181        /// </summary>
 1182        /// <param name="range">
 1183        /// Specifies the range of bytes to be cleared. Both the start and
 1184        /// end of the range must be specified.  For a page clear operation,
 1185        /// the page range can be up to the value of the blob's full size.
 1186        /// Given that pages must be aligned with 512-byte boundaries, the
 1187        /// start of the range must be a modulus of 512 and the end of the
 1188        /// range must be a modulus of 512 – 1.  Examples of valid byte ranges
 1189        /// are 0-511, 512-1023, etc.
 1190        /// </param>
 1191        /// <param name="conditions">
 1192        /// Optional <see cref="PageBlobRequestConditions"/> to add
 1193        /// conditions on clearing pages from this page blob.
 1194        /// </param>
 1195        /// <param name="cancellationToken">
 1196        /// Optional <see cref="CancellationToken"/> to propagate
 1197        /// notifications that the operation should be cancelled.
 1198        /// </param>
 1199        /// <returns>
 1200        /// A <see cref="Response{PageInfo}"/> describing the
 1201        /// state of the updated pages.
 1202        /// </returns>
 1203        /// <remarks>
 1204        /// A <see cref="RequestFailedException"/> will be thrown if
 1205        /// a failure occurs.
 1206        /// </remarks>
 1207        public virtual async Task<Response<PageInfo>> ClearPagesAsync(
 1208            HttpRange range,
 1209            PageBlobRequestConditions conditions = default,
 1210            CancellationToken cancellationToken = default) =>
 1211            await ClearPagesInternal(
 1212                range,
 1213                conditions,
 1214                true, // async
 1215                cancellationToken)
 1216                .ConfigureAwait(false);
 1217
 1218        /// <summary>
 1219        /// The <see cref="ClearPagesInternal"/> operation clears one or more
 1220        /// pages from the page blob, as specificed by the <paramref name="range"/>.
 1221        ///
 1222        /// For more information, see
 1223        /// <see href="https://docs.microsoft.com/rest/api/storageservices/put-page">
 1224        /// Put Page</see>.
 1225        /// </summary>
 1226        /// <param name="range">
 1227        /// Specifies the range of bytes to be cleared. Both the start and
 1228        /// end of the range must be specified.  For a page clear operation,
 1229        /// the page range can be up to the value of the blob's full size.
 1230        /// Given that pages must be aligned with 512-byte boundaries, the
 1231        /// start of the range must be a modulus of 512 and the end of the
 1232        /// range must be a modulus of 512 – 1.  Examples of valid byte ranges
 1233        /// are 0-511, 512-1023, etc.
 1234        /// </param>
 1235        /// <param name="conditions">
 1236        /// Optional <see cref="PageBlobRequestConditions"/> to add
 1237        /// conditions on clearing pages from this page blob.
 1238        /// </param>
 1239        /// <param name="async">
 1240        /// Whether to invoke the operation asynchronously.
 1241        /// </param>
 1242        /// <param name="cancellationToken">
 1243        /// Optional <see cref="CancellationToken"/> to propagate
 1244        /// notifications that the operation should be cancelled.
 1245        /// </param>
 1246        /// <returns>
 1247        /// A <see cref="Response{PageInfo}"/> describing the
 1248        /// state of the updated pages.
 1249        /// </returns>
 1250        /// <remarks>
 1251        /// A <see cref="RequestFailedException"/> will be thrown if
 1252        /// a failure occurs.
 1253        /// </remarks>
 1254        private async Task<Response<PageInfo>> ClearPagesInternal(
 1255            HttpRange range,
 1256            PageBlobRequestConditions conditions,
 1257            bool async,
 1258            CancellationToken cancellationToken)
 1259        {
 1260            using (Pipeline.BeginLoggingScope(nameof(PageBlobClient)))
 1261            {
 1262                Pipeline.LogMethodEnter(
 1263                    nameof(PageBlobClient),
 1264                    message:
 1265                    $"{nameof(Uri)}: {Uri}\n" +
 1266                    $"{nameof(conditions)}: {conditions}");
 1267                try
 1268                {
 1269                    return await BlobRestClient.PageBlob.ClearPagesAsync(
 1270                        ClientDiagnostics,
 1271                        Pipeline,
 1272                        Uri,
 1273                        contentLength: default,
 1274                        version: Version.ToVersionString(),
 1275                        range: range.ToString(),
 1276                        leaseId: conditions?.LeaseId,
 1277                        encryptionKey: CustomerProvidedKey?.EncryptionKey,
 1278                        encryptionKeySha256: CustomerProvidedKey?.EncryptionKeyHash,
 1279                        encryptionAlgorithm: CustomerProvidedKey?.EncryptionAlgorithm,
 1280                        encryptionScope: EncryptionScope,
 1281                        ifSequenceNumberLessThanOrEqualTo: conditions?.IfSequenceNumberLessThanOrEqual,
 1282                        ifSequenceNumberLessThan: conditions?.IfSequenceNumberLessThan,
 1283                        ifSequenceNumberEqualTo: conditions?.IfSequenceNumberEqual,
 1284                        ifModifiedSince: conditions?.IfModifiedSince,
 1285                        ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
 1286                        ifMatch: conditions?.IfMatch,
 1287                        ifNoneMatch: conditions?.IfNoneMatch,
 1288                        ifTags: conditions?.TagConditions,
 1289                        async: async,
 1290                        operationName: $"{nameof(PageBlobClient)}.{nameof(ClearPages)}",
 1291                        cancellationToken: cancellationToken)
 1292                        .ConfigureAwait(false);
 1293                }
 1294                catch (Exception ex)
 1295                {
 1296                    Pipeline.LogException(ex);
 1297                    throw;
 1298                }
 1299                finally
 1300                {
 1301                    Pipeline.LogMethodExit(nameof(PageBlobClient));
 1302                }
 1303            }
 1304        }
 1305        #endregion ClearPages
 1306
 1307        #region GetPageRanges
 1308        /// <summary>
 1309        /// The <see cref="GetPageRanges"/> operation returns the list of
 1310        /// valid page ranges for a page blob or snapshot of a page blob.
 1311        ///
 1312        /// For more information, see
 1313        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/get-page-ranges">
 1314        /// Get Page Ranges</see>.
 1315        /// </summary>
 1316        /// <param name="range">
 1317        /// Optionally specifies the range of bytes over which to list ranges,
 1318        /// inclusively. If omitted, then all ranges for the blob are returned.
 1319        /// </param>
 1320        /// <param name="snapshot">
 1321        /// Optionally specifies the blob snapshot to retrieve page ranges
 1322        /// information from. For more information on working with blob snapshots,
 1323        /// <see href="https://docs.microsoft.com/rest/api/storageservices/creating-a-snapshot-of-a-blob">
 1324        /// Create a snapshot of a blob</see>.
 1325        /// </param>
 1326        /// <param name="conditions">
 1327        /// Optional <see cref="PageBlobRequestConditions"/> to add
 1328        /// conditions on getting page ranges for the this blob.
 1329        /// </param>
 1330        /// <param name="cancellationToken">
 1331        /// Optional <see cref="CancellationToken"/> to propagate
 1332        /// notifications that the operation should be cancelled.
 1333        /// </param>
 1334        /// <returns>
 1335        /// A <see cref="Response{PageRangesInfo}"/> describing the
 1336        /// valid page ranges for this blob.
 1337        /// </returns>
 1338        /// <remarks>
 1339        /// A <see cref="RequestFailedException"/> will be thrown if
 1340        /// a failure occurs.
 1341        /// </remarks>
 1342        public virtual Response<PageRangesInfo> GetPageRanges(
 1343            HttpRange? range = default,
 1344            string snapshot = default,
 1345            PageBlobRequestConditions conditions = default,
 1346            CancellationToken cancellationToken = default) =>
 1347            GetPageRangesInternal(
 1348                range,
 1349                snapshot,
 1350                conditions,
 1351                false, // async
 1352                cancellationToken)
 1353                .EnsureCompleted();
 1354
 1355        /// <summary>
 1356        /// The <see cref="GetPageRangesAsync"/> operation returns the list of
 1357        /// valid page ranges for a page blob or snapshot of a page blob.
 1358        ///
 1359        /// For more information, see
 1360        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/get-page-ranges">
 1361        /// Get Page Ranges</see>.
 1362        /// </summary>
 1363        /// <param name="range">
 1364        /// Optionally specifies the range of bytes over which to list ranges,
 1365        /// inclusively. If omitted, then all ranges for the blob are returned.
 1366        /// </param>
 1367        /// <param name="snapshot">
 1368        /// Optionally specifies the blob snapshot to retrieve page ranges
 1369        /// information from. For more information on working with blob snapshots,
 1370        /// <see href="https://docs.microsoft.com/rest/api/storageservices/creating-a-snapshot-of-a-blob">
 1371        /// Create a snapshot of a blob</see>.
 1372        /// </param>
 1373        /// <param name="conditions">
 1374        /// Optional <see cref="PageBlobRequestConditions"/> to add
 1375        /// conditions on getting page ranges for the this 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{PageRangesInfo}"/> describing the
 1383        /// valid page ranges for this blob.
 1384        /// </returns>
 1385        /// <remarks>
 1386        /// A <see cref="RequestFailedException"/> will be thrown if
 1387        /// a failure occurs.
 1388        /// </remarks>
 1389        public virtual async Task<Response<PageRangesInfo>> GetPageRangesAsync(
 1390            HttpRange? range = default,
 1391            string snapshot = default,
 1392            PageBlobRequestConditions conditions = default,
 1393            CancellationToken cancellationToken = default) =>
 1394            await GetPageRangesInternal(
 1395                range,
 1396                snapshot,
 1397                conditions,
 1398                true, // async
 1399                cancellationToken)
 1400                .ConfigureAwait(false);
 1401
 1402        /// <summary>
 1403        /// The <see cref="GetPageRangesInternal"/> operation returns the list
 1404        /// of valid page ranges for a page blob or snapshot of a page blob.
 1405        ///
 1406        /// For more information, see For more information, see
 1407        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/get-page-ranges">
 1408        /// Get Page Ranges</see>.
 1409        /// </summary>
 1410        /// <param name="range">
 1411        /// Optionally specifies the range of bytes over which to list ranges,
 1412        /// inclusively. If omitted, then all ranges for the blob are returned.
 1413        /// </param>
 1414        /// <param name="snapshot">
 1415        /// Optionally specifies the blob snapshot to retrieve page ranges
 1416        /// information from. For more information on working with blob snapshots,
 1417        /// <see href="https://docs.microsoft.com/rest/api/storageservices/creating-a-snapshot-of-a-blob">
 1418        /// Create a snapshot of a blob</see>.
 1419        /// </param>
 1420        /// <param name="conditions">
 1421        /// Optional <see cref="PageBlobRequestConditions"/> to add
 1422        /// conditions on getting page ranges for the this blob.
 1423        /// </param>
 1424        /// <param name="async">
 1425        /// Whether to invoke the operation asynchronously.
 1426        /// </param>
 1427        /// <param name="cancellationToken">
 1428        /// Optional <see cref="CancellationToken"/> to propagate
 1429        /// notifications that the operation should be cancelled.
 1430        /// </param>
 1431        /// <returns>
 1432        /// A <see cref="Response{PageRangesInfo}"/> describing the
 1433        /// valid page ranges for this blob.
 1434        /// </returns>
 1435        /// <remarks>
 1436        /// A <see cref="RequestFailedException"/> will be thrown if
 1437        /// a failure occurs.
 1438        /// </remarks>
 1439        private async Task<Response<PageRangesInfo>> GetPageRangesInternal(
 1440            HttpRange? range,
 1441            string snapshot,
 1442            PageBlobRequestConditions conditions,
 1443            bool async,
 1444            CancellationToken cancellationToken)
 1445        {
 1446            using (Pipeline.BeginLoggingScope(nameof(PageBlobClient)))
 1447            {
 1448                Pipeline.LogMethodEnter(
 1449                    nameof(PageBlobClient),
 1450                    message:
 1451                    $"{nameof(Uri)}: {Uri}\n" +
 1452                    $"{nameof(snapshot)}: {snapshot}\n" +
 1453                    $"{nameof(conditions)}: {conditions}");
 1454                try
 1455                {
 1456                    Response<PageRangesInfoInternal> response = await BlobRestClient.PageBlob.GetPageRangesAsync(
 1457                        ClientDiagnostics,
 1458                        Pipeline,
 1459                        Uri,
 1460                        version: Version.ToVersionString(),
 1461                        snapshot: snapshot,
 1462                        range: range?.ToString(),
 1463                        leaseId: conditions?.LeaseId,
 1464                        ifModifiedSince: conditions?.IfModifiedSince,
 1465                        ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
 1466                        ifMatch: conditions?.IfMatch,
 1467                        ifNoneMatch: conditions?.IfNoneMatch,
 1468                        ifTags: conditions?.TagConditions,
 1469                        async: async,
 1470                        operationName: $"{nameof(PageBlobClient)}.{nameof(GetPageRanges)}",
 1471                        cancellationToken: cancellationToken)
 1472                        .ConfigureAwait(false);
 1473
 1474                    // Return an exploding Response on 304
 1475                    return response.IsUnavailable() ?
 1476                        response.GetRawResponse().AsNoBodyResponse<PageRangesInfo>() :
 1477                        Response.FromValue(new PageRangesInfo(response.Value), response.GetRawResponse());
 1478                }
 1479                catch (Exception ex)
 1480                {
 1481                    Pipeline.LogException(ex);
 1482                    throw;
 1483                }
 1484                finally
 1485                {
 1486                    Pipeline.LogMethodExit(nameof(PageBlobClient));
 1487                }
 1488            }
 1489        }
 1490        #endregion GetPageRanges
 1491
 1492        #region GetPageRangesDiff
 1493        /// <summary>
 1494        /// The <see cref="GetPageRangesDiff"/>
 1495        /// operation returns the list of page ranges that differ between a
 1496        /// <paramref name="previousSnapshot"/> and this page blob. Changed pages
 1497        /// include both updated and cleared pages.
 1498        ///
 1499        /// For more information, see
 1500        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/get-page-ranges">
 1501        /// Get Page Ranges</see>.
 1502        /// </summary>
 1503        /// <param name="range">
 1504        /// Optionally specifies the range of bytes over which to list ranges,
 1505        /// inclusively. If omitted, then all ranges for the blob are returned.
 1506        /// </param>
 1507        /// <param name="snapshot">
 1508        /// Optionally specifies the blob snapshot to retrieve page ranges
 1509        /// information from. For more information on working with blob snapshots,
 1510        /// <see href="https://docs.microsoft.com/rest/api/storageservices/creating-a-snapshot-of-a-blob">
 1511        /// Create a snapshot of a blob</see>.
 1512        /// </param>
 1513        /// <param name="previousSnapshot">
 1514        /// Specifies that the response will contain only pages that were
 1515        /// changed between target blob and previous snapshot.  Changed pages
 1516        /// include both updated and cleared pages. The target blob may be a
 1517        /// snapshot, as long as the snapshot specified by
 1518        /// <paramref name="previousSnapshot"/> is the older of the two.
 1519        /// </param>
 1520        /// <param name="conditions">
 1521        /// Optional <see cref="PageBlobRequestConditions"/> to add
 1522        /// conditions on getting page ranges for the this blob.
 1523        /// </param>
 1524        /// <param name="cancellationToken">
 1525        /// Optional <see cref="CancellationToken"/> to propagate
 1526        /// notifications that the operation should be cancelled.
 1527        /// </param>
 1528        /// <returns>
 1529        /// A <see cref="Response{PageRangesInfo}"/> describing the
 1530        /// valid page ranges for this blob.
 1531        /// </returns>
 1532        /// <remarks>
 1533        /// A <see cref="RequestFailedException"/> will be thrown if
 1534        /// a failure occurs.
 1535        /// </remarks>
 1536        public virtual Response<PageRangesInfo> GetPageRangesDiff(
 1537            HttpRange? range = default,
 1538            string snapshot = default,
 1539            string previousSnapshot = default,
 1540            PageBlobRequestConditions conditions = default,
 1541            CancellationToken cancellationToken = default) =>
 1542            GetPageRangesDiffInternal(
 1543                range,
 1544                snapshot,
 1545                previousSnapshot,
 1546                previousSnapshotUri: default,
 1547                conditions,
 1548                async: false,
 1549                operationName: $"{nameof(PageBlobClient)}.{nameof(GetPageRangesDiff)}",
 1550                cancellationToken)
 1551                .EnsureCompleted();
 1552
 1553        /// <summary>
 1554        /// The <see cref="GetPageRangesDiffAsync"/>
 1555        /// operation returns the list of page ranges that differ between a
 1556        /// <paramref name="previousSnapshot"/> and this page blob. Changed pages
 1557        /// include both updated and cleared pages.
 1558        ///
 1559        /// For more information, see
 1560        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/get-page-ranges">
 1561        /// Get Page Ranges</see>.
 1562        /// </summary>
 1563        /// <param name="range">
 1564        /// Optionally specifies the range of bytes over which to list ranges,
 1565        /// inclusively. If omitted, then all ranges for the blob are returned.
 1566        /// </param>
 1567        /// <param name="snapshot">
 1568        /// Optionally specifies the blob snapshot to retrieve page ranges
 1569        /// information from. For more information on working with blob snapshots,
 1570        /// <see href="https://docs.microsoft.com/rest/api/storageservices/creating-a-snapshot-of-a-blob">
 1571        /// Create a snapshot of a blob</see>.
 1572        /// </param>
 1573        /// <param name="previousSnapshot">
 1574        /// Specifies that the response will contain only pages that were
 1575        /// changed between target blob and previous snapshot.  Changed pages
 1576        /// include both updated and cleared pages. The target blob may be a
 1577        /// snapshot, as long as the snapshot specified by
 1578        /// <paramref name="previousSnapshot"/> is the older of the two.
 1579        /// </param>
 1580        /// <param name="conditions">
 1581        /// Optional <see cref="PageBlobRequestConditions"/> to add
 1582        /// conditions on getting page ranges for the this blob.
 1583        /// </param>
 1584        /// <param name="cancellationToken">
 1585        /// Optional <see cref="CancellationToken"/> to propagate
 1586        /// notifications that the operation should be cancelled.
 1587        /// </param>
 1588        /// <returns>
 1589        /// A <see cref="Response{PageRangesInfo}"/> describing the
 1590        /// valid page ranges for this blob.
 1591        /// </returns>
 1592        /// <remarks>
 1593        /// A <see cref="RequestFailedException"/> will be thrown if
 1594        /// a failure occurs.
 1595        /// </remarks>
 1596        public virtual async Task<Response<PageRangesInfo>> GetPageRangesDiffAsync(
 1597            HttpRange? range = default,
 1598            string snapshot = default,
 1599            string previousSnapshot = default,
 1600            PageBlobRequestConditions conditions = default,
 1601            CancellationToken cancellationToken = default) =>
 1602            await GetPageRangesDiffInternal(
 1603                range,
 1604                snapshot,
 1605                previousSnapshot,
 1606                previousSnapshotUri: default,
 1607                conditions,
 1608                async: true,
 1609                operationName: $"{nameof(PageBlobClient)}.{nameof(GetPageRangesDiff)}",
 1610                cancellationToken)
 1611                .ConfigureAwait(false);
 1612
 1613        /// <summary>
 1614        /// The <see cref="GetPageRangesDiffInternal"/> operation returns the
 1615        /// list of page ranges that differ between a
 1616        /// <paramref name="previousSnapshot"/> and this page blob. Changed pages
 1617        /// include both updated and cleared pages.
 1618        ///
 1619        /// For more information, see
 1620        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/get-page-ranges">
 1621        /// Get Page Ranges</see>.
 1622        /// </summary>
 1623        /// <param name="range">
 1624        /// Optionally specifies the range of bytes over which to list ranges,
 1625        /// inclusively. If omitted, then all ranges for the blob are returned.
 1626        /// </param>
 1627        /// <param name="snapshot">
 1628        /// Optionally specifies the blob snapshot to retrieve page ranges
 1629        /// information from. For more information on working with blob snapshots,
 1630        /// <see href="https://docs.microsoft.com/rest/api/storageservices/creating-a-snapshot-of-a-blob">
 1631        /// Create a snapshot of a blob</see>.
 1632        /// </param>
 1633        /// <param name="previousSnapshot">
 1634        /// Specifies that the response will contain only pages that were
 1635        /// changed between target blob and previous snapshot.  Changed pages
 1636        /// include both updated and cleared pages. The target blob may be a
 1637        /// snapshot, as long as the snapshot specified by
 1638        /// <paramref name="previousSnapshot"/> is the older of the two.
 1639        /// </param>
 1640        /// <param name="previousSnapshotUri">
 1641        /// This parameter only works with managed disk storage accounts.
 1642        /// Specifies that the response will contain only pages that were
 1643        /// changed between target blob and previous snapshot.  Changed pages
 1644        /// include both updated and cleared pages. The target blob may be a
 1645        /// snapshot, as long as the snapshot specified by
 1646        /// <paramref name="previousSnapshotUri"/> is the older of the two.
 1647        /// </param>
 1648        /// <param name="conditions">
 1649        /// Optional <see cref="PageBlobRequestConditions"/> to add
 1650        /// conditions on getting page ranges for the this blob.
 1651        /// </param>
 1652        /// <param name="async">
 1653        /// Whether to invoke the operation asynchronously.
 1654        /// </param>
 1655        /// <param name="operationName">
 1656        /// The name of the operation.
 1657        /// </param>
 1658        /// <param name="cancellationToken">
 1659        /// Optional <see cref="CancellationToken"/> to propagate
 1660        /// notifications that the operation should be cancelled.
 1661        /// </param>
 1662        /// <returns>
 1663        /// A <see cref="Response{PageRangesInfo}"/> describing the
 1664        /// valid page ranges for this blob.
 1665        /// </returns>
 1666        /// <remarks>
 1667        /// A <see cref="RequestFailedException"/> will be thrown if
 1668        /// a failure occurs.
 1669        /// </remarks>
 1670        private async Task<Response<PageRangesInfo>> GetPageRangesDiffInternal(
 1671            HttpRange? range,
 1672            string snapshot,
 1673            string previousSnapshot,
 1674            Uri previousSnapshotUri,
 1675            PageBlobRequestConditions conditions,
 1676            bool async,
 1677            string operationName,
 1678            CancellationToken cancellationToken)
 1679        {
 1680            using (Pipeline.BeginLoggingScope(nameof(PageBlobClient)))
 1681            {
 1682                Pipeline.LogMethodEnter(
 1683                    nameof(PageBlobClient),
 1684                    message:
 1685                    $"{nameof(Uri)}: {Uri}\n" +
 1686                    $"{nameof(snapshot)}: {snapshot}\n" +
 1687                    $"{nameof(previousSnapshot)}: {previousSnapshot}\n" +
 1688                    $"{nameof(previousSnapshotUri)}: {previousSnapshotUri}\n" +
 1689                    $"{nameof(conditions)}: {conditions}");
 1690                try
 1691                {
 1692                    Response<PageRangesInfoInternal> response = await BlobRestClient.PageBlob.GetPageRangesDiffAsync(
 1693                        ClientDiagnostics,
 1694                        Pipeline,
 1695                        Uri,
 1696                        version: Version.ToVersionString(),
 1697                        snapshot: snapshot,
 1698                        prevsnapshot: previousSnapshot,
 1699                        prevSnapshotUrl: previousSnapshotUri,
 1700                        range: range?.ToString(),
 1701                        leaseId: conditions?.LeaseId,
 1702                        ifModifiedSince: conditions?.IfModifiedSince,
 1703                        ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
 1704                        ifMatch: conditions?.IfMatch,
 1705                        ifNoneMatch: conditions?.IfNoneMatch,
 1706                        ifTags: conditions?.TagConditions,
 1707                        async: async,
 1708                        operationName: operationName,
 1709                        cancellationToken: cancellationToken)
 1710                        .ConfigureAwait(false);
 1711
 1712                    // Return an exploding Response on 304
 1713                    return response.IsUnavailable() ?
 1714                        response.GetRawResponse().AsNoBodyResponse<PageRangesInfo>() :
 1715                        Response.FromValue(new PageRangesInfo(response.Value), response.GetRawResponse());
 1716                }
 1717                catch (Exception ex)
 1718                {
 1719                    Pipeline.LogException(ex);
 1720                    throw;
 1721                }
 1722                finally
 1723                {
 1724                    Pipeline.LogMethodExit(nameof(PageBlobClient));
 1725                }
 1726            }
 1727        }
 1728        #endregion GetPageRangesDiff
 1729
 1730        #region GetManagedDiskPageRangesDiff
 1731        /// <summary>
 1732        /// The <see cref="GetManagedDiskPageRangesDiff"/>
 1733        /// operation returns the list of page ranges that differ between a
 1734        /// <paramref name="previousSnapshotUri"/> and this page blob. Changed pages
 1735        /// include both updated and cleared pages.  This API only works with
 1736        /// managed disk storage accounts.
 1737        ///
 1738        /// For more information, see
 1739        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/get-page-ranges">
 1740        /// Get Page Ranges</see>.
 1741        /// </summary>
 1742        /// <param name="range">
 1743        /// Optionally specifies the range of bytes over which to list ranges,
 1744        /// inclusively. If omitted, then all ranges for the blob are returned.
 1745        /// </param>
 1746        /// <param name="snapshot">
 1747        /// Optionally specifies the blob snapshot to retrieve page ranges
 1748        /// information from. For more information on working with blob snapshots,
 1749        /// <see href="https://docs.microsoft.com/rest/api/storageservices/creating-a-snapshot-of-a-blob">
 1750        /// Create a snapshot of a blob</see>.
 1751        /// </param>
 1752        /// <param name="previousSnapshotUri">
 1753        /// This parameter only works with managed disk storage accounts.
 1754        /// Specifies that the response will contain only pages that were
 1755        /// changed between target blob and previous snapshot.  Changed pages
 1756        /// include both updated and cleared pages. The target blob may be a
 1757        /// snapshot, as long as the snapshot specified by
 1758        /// <paramref name="previousSnapshotUri"/> is the older of the two.
 1759        /// </param>
 1760        /// <param name="conditions">
 1761        /// Optional <see cref="PageBlobRequestConditions"/> to add
 1762        /// conditions on getting page ranges for the this blob.
 1763        /// </param>
 1764        /// <param name="cancellationToken">
 1765        /// Optional <see cref="CancellationToken"/> to propagate
 1766        /// notifications that the operation should be cancelled.
 1767        /// </param>
 1768        /// <returns>
 1769        /// A <see cref="Response{PageRangesInfo}"/> describing the
 1770        /// valid page ranges for this blob.
 1771        /// </returns>
 1772        /// <remarks>
 1773        /// A <see cref="RequestFailedException"/> will be thrown if
 1774        /// a failure occurs.
 1775        /// </remarks>
 1776        public virtual Response<PageRangesInfo> GetManagedDiskPageRangesDiff(
 1777            HttpRange? range = default,
 1778            string snapshot = default,
 1779            Uri previousSnapshotUri = default,
 1780            PageBlobRequestConditions conditions = default,
 1781            CancellationToken cancellationToken = default) =>
 1782            GetPageRangesDiffInternal(
 1783                range,
 1784                snapshot,
 1785                previousSnapshot: default,
 1786                previousSnapshotUri,
 1787                conditions,
 1788                async: false,
 1789                operationName: $"{nameof(PageBlobClient)}.{nameof(GetManagedDiskPageRangesDiff)}",
 1790                cancellationToken)
 1791                .EnsureCompleted();
 1792
 1793        /// <summary>
 1794        /// The <see cref="GetManagedDiskPageRangesDiffAsync"/>
 1795        /// operation returns the list of page ranges that differ between a
 1796        /// <paramref name="previousSnapshotUri"/> and this page blob. Changed pages
 1797        /// include both updated and cleared pages.  This API only works with
 1798        /// managed disk storage accounts.
 1799        ///
 1800        /// For more information, see
 1801        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/get-page-ranges">
 1802        /// Get Page Ranges</see>.
 1803        /// </summary>
 1804        /// <param name="range">
 1805        /// Optionally specifies the range of bytes over which to list ranges,
 1806        /// inclusively. If omitted, then all ranges for the blob are returned.
 1807        /// </param>
 1808        /// <param name="snapshot">
 1809        /// Optionally specifies the blob snapshot to retrieve page ranges
 1810        /// information from. For more information on working with blob snapshots,
 1811        /// <see href="https://docs.microsoft.com/rest/api/storageservices/creating-a-snapshot-of-a-blob">
 1812        /// Create a snapshot of a blob</see>.
 1813        /// </param>
 1814        /// <param name="previousSnapshotUri">
 1815        /// This parameter only works with managed disk storage accounts.
 1816        /// Specifies that the response will contain only pages that were
 1817        /// changed between target blob and previous snapshot.  Changed pages
 1818        /// include both updated and cleared pages. The target blob may be a
 1819        /// snapshot, as long as the snapshot specified by
 1820        /// <paramref name="previousSnapshotUri"/> is the older of the two.
 1821        /// </param>
 1822        /// <param name="conditions">
 1823        /// Optional <see cref="PageBlobRequestConditions"/> to add
 1824        /// conditions on getting page ranges for the this blob.
 1825        /// </param>
 1826        /// <param name="cancellationToken">
 1827        /// Optional <see cref="CancellationToken"/> to propagate
 1828        /// notifications that the operation should be cancelled.
 1829        /// </param>
 1830        /// <returns>
 1831        /// A <see cref="Response{PageRangesInfo}"/> describing the
 1832        /// valid page ranges for this blob.
 1833        /// </returns>
 1834        /// <remarks>
 1835        /// A <see cref="RequestFailedException"/> will be thrown if
 1836        /// a failure occurs.
 1837        /// </remarks>
 1838        public virtual async Task<Response<PageRangesInfo>> GetManagedDiskPageRangesDiffAsync(
 1839            HttpRange? range = default,
 1840            string snapshot = default,
 1841            Uri previousSnapshotUri = default,
 1842            PageBlobRequestConditions conditions = default,
 1843            CancellationToken cancellationToken = default) =>
 1844            await GetPageRangesDiffInternal(
 1845                range,
 1846                snapshot,
 1847                previousSnapshot: default,
 1848                previousSnapshotUri,
 1849                conditions,
 1850                async: true,
 1851                operationName: $"{nameof(PageBlobClient)}.{nameof(GetManagedDiskPageRangesDiff)}",
 1852                cancellationToken)
 1853                .ConfigureAwait(false);
 1854
 1855        #endregion GetManagedDiskPageRangesDiff
 1856
 1857        #region Resize
 1858        /// <summary>
 1859        /// The <see cref="Resize"/> operation resizes the page blob to
 1860        /// the specified size (which must be a multiple of 512).  If the
 1861        /// specified value is less than the current size of the blob, then
 1862        /// all pages above the specified value are cleared.
 1863        ///
 1864        /// For more information, see
 1865        /// <see href="https://docs.microsoft.com/rest/api/storageservices/set-blob-properties">
 1866        /// Set Blob Properties</see>.
 1867        /// </summary>
 1868        /// <param name="size">
 1869        /// Specifies the maximum size for the page blob, up to 8 TB.  The
 1870        /// size must be aligned to a 512-byte boundary.  If the specified
 1871        /// value is less than the current size of the blob, then all pages
 1872        /// above the specified value are cleared.
 1873        /// </param>
 1874        /// <param name="conditions">
 1875        /// Optional <see cref="PageBlobRequestConditions"/> to add
 1876        /// conditions on the resize of this page blob.
 1877        /// </param>
 1878        /// <param name="cancellationToken">
 1879        /// Optional <see cref="CancellationToken"/> to propagate
 1880        /// notifications that the operation should be cancelled.
 1881        /// </param>
 1882        /// <returns>
 1883        /// A <see cref="Response{PageBlobInfo}"/> describing the resized
 1884        /// page blob.
 1885        /// </returns>
 1886        /// <remarks>
 1887        /// A <see cref="RequestFailedException"/> will be thrown if
 1888        /// a failure occurs.
 1889        /// </remarks>
 1890        public virtual Response<PageBlobInfo> Resize(
 1891            long size,
 1892            PageBlobRequestConditions conditions = default,
 1893            CancellationToken cancellationToken = default) =>
 1894            ResizeInternal(
 1895                size,
 1896                conditions,
 1897                false, // async
 1898                cancellationToken)
 1899                .EnsureCompleted();
 1900
 1901        /// <summary>
 1902        /// The <see cref="ResizeAsync"/> operation resizes the page blob to
 1903        /// the specified size (which must be a multiple of 512).  If the
 1904        /// specified value is less than the current size of the blob, then
 1905        /// all pages above the specified value are cleared.
 1906        ///
 1907        /// For more information, see
 1908        /// <see href="https://docs.microsoft.com/rest/api/storageservices/set-blob-properties">
 1909        /// Set Blob Properties</see>.
 1910        /// </summary>
 1911        /// <param name="size">
 1912        /// Specifies the maximum size for the page blob, up to 8 TB.  The
 1913        /// size must be aligned to a 512-byte boundary.  If the specified
 1914        /// value is less than the current size of the blob, then all pages
 1915        /// above the specified value are cleared.
 1916        /// </param>
 1917        /// <param name="conditions">
 1918        /// Optional <see cref="PageBlobRequestConditions"/> to add
 1919        /// conditions on the resize of this page blob.
 1920        /// </param>
 1921        /// <param name="cancellationToken">
 1922        /// Optional <see cref="CancellationToken"/> to propagate
 1923        /// notifications that the operation should be cancelled.
 1924        /// </param>
 1925        /// <returns>
 1926        /// A <see cref="Response{PageBlobInfo}"/> describing the resized
 1927        /// page blob.
 1928        /// </returns>
 1929        /// <remarks>
 1930        /// A <see cref="RequestFailedException"/> will be thrown if
 1931        /// a failure occurs.
 1932        /// </remarks>
 1933        public virtual async Task<Response<PageBlobInfo>> ResizeAsync(
 1934            long size,
 1935            PageBlobRequestConditions conditions = default,
 1936            CancellationToken cancellationToken = default) =>
 1937            await ResizeInternal(
 1938                size,
 1939                conditions,
 1940                true, // async
 1941                cancellationToken)
 1942                .ConfigureAwait(false);
 1943
 1944        /// <summary>
 1945        /// The <see cref="ResizeAsync"/> operation resizes the page blob to
 1946        /// the specified size (which must be a multiple of 512).  If the
 1947        /// specified value is less than the current size of the blob, then
 1948        /// all pages above the specified value are cleared.
 1949        ///
 1950        /// For more information, see
 1951        /// <see href="https://docs.microsoft.com/rest/api/storageservices/set-blob-properties">
 1952        /// Set Blob Properties</see>.
 1953        /// </summary>
 1954        /// <param name="size">
 1955        /// Specifies the maximum size for the page blob, up to 8 TB.  The
 1956        /// size must be aligned to a 512-byte boundary.  If the specified
 1957        /// value is less than the current size of the blob, then all pages
 1958        /// above the specified value are cleared.
 1959        /// </param>
 1960        /// <param name="conditions">
 1961        /// Optional <see cref="PageBlobRequestConditions"/> to add
 1962        /// conditions on the resize of this page blob.
 1963        /// </param>
 1964        /// <param name="async">
 1965        /// Whether to invoke the operation asynchronously.
 1966        /// </param>
 1967        /// <param name="cancellationToken">
 1968        /// Optional <see cref="CancellationToken"/> to propagate
 1969        /// notifications that the operation should be cancelled.
 1970        /// </param>
 1971        /// <returns>
 1972        /// A <see cref="Response{PageBlobInfo}"/> describing the resized
 1973        /// page blob.
 1974        /// </returns>
 1975        /// <remarks>
 1976        /// A <see cref="RequestFailedException"/> will be thrown if
 1977        /// a failure occurs.
 1978        /// </remarks>
 1979        private async Task<Response<PageBlobInfo>> ResizeInternal(
 1980            long size,
 1981            PageBlobRequestConditions conditions,
 1982            bool async,
 1983            CancellationToken cancellationToken)
 1984        {
 1985            using (Pipeline.BeginLoggingScope(nameof(PageBlobClient)))
 1986            {
 1987                Pipeline.LogMethodEnter(
 1988                    nameof(PageBlobClient),
 1989                    message:
 1990                    $"{nameof(Uri)}: {Uri}\n" +
 1991                    $"{nameof(size)}: {size}\n" +
 1992                    $"{nameof(conditions)}: {conditions}");
 1993                try
 1994                {
 1995                    return await BlobRestClient.PageBlob.ResizeAsync(
 1996                        ClientDiagnostics,
 1997                        Pipeline,
 1998                        Uri,
 1999                        blobContentLength: size,
 2000                        version: Version.ToVersionString(),
 2001                        leaseId: conditions?.LeaseId,
 2002                        encryptionKey: CustomerProvidedKey?.EncryptionKey,
 2003                        encryptionKeySha256: CustomerProvidedKey?.EncryptionKeyHash,
 2004                        encryptionAlgorithm: CustomerProvidedKey?.EncryptionAlgorithm,
 2005                        encryptionScope: EncryptionScope,
 2006                        ifModifiedSince: conditions?.IfModifiedSince,
 2007                        ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
 2008                        ifMatch: conditions?.IfMatch,
 2009                        ifNoneMatch: conditions?.IfNoneMatch,
 2010                        ifTags: conditions?.TagConditions,
 2011                        async: async,
 2012                        operationName: $"{nameof(PageBlobClient)}.{nameof(Resize)}",
 2013                        cancellationToken: cancellationToken)
 2014                        .ConfigureAwait(false);
 2015                }
 2016                catch (Exception ex)
 2017                {
 2018                    Pipeline.LogException(ex);
 2019                    throw;
 2020                }
 2021                finally
 2022                {
 2023                    Pipeline.LogMethodExit(nameof(PageBlobClient));
 2024                }
 2025            }
 2026        }
 2027        #endregion Resize
 2028
 2029        #region UpdateSequenceNumber
 2030        /// <summary>
 2031        /// The <see cref="UpdateSequenceNumber"/> operation changes the
 2032        /// sequence number <paramref name="action"/> and <paramref name="sequenceNumber"/>
 2033        /// for this page blob.
 2034        ///
 2035        /// For more information, see
 2036        /// <see href="https://docs.microsoft.com/rest/api/storageservices/set-blob-properties">
 2037        /// Set Blob Properties</see>.
 2038        /// </summary>
 2039        /// <param name="action">
 2040        /// Specifies how the service should modify the blob's sequence number.
 2041        /// <see cref="SequenceNumberAction.Max"/> sets the sequence number to
 2042        /// be the higher of the value included with the request and the value
 2043        /// currently stored for the blob.  <see cref="SequenceNumberAction.Update"/>
 2044        /// sets the sequence number to the <paramref name="sequenceNumber"/>
 2045        /// value.  <see cref="SequenceNumberAction.Increment"/> increments
 2046        /// the value of the sequence number by 1.  If specifying
 2047        /// <see cref="SequenceNumberAction.Increment"/>, do not include the
 2048        /// <paramref name="sequenceNumber"/> because that will throw a
 2049        /// <see cref="RequestFailedException"/>.
 2050        /// </param>
 2051        /// <param name="sequenceNumber">
 2052        /// An updated sequence number of your choosing, if
 2053        /// <paramref name="action"/> is <see cref="SequenceNumberAction.Max"/>
 2054        /// or <see cref="SequenceNumberAction.Update"/>.  The value should
 2055        /// not be provided if <paramref name="action"/> is
 2056        /// <see cref="SequenceNumberAction.Increment"/>.  The sequence number
 2057        /// is a user-controlled property that you can use to track requests
 2058        /// and manage concurrency issues via <see cref="PageBlobRequestConditions"/>.
 2059        /// </param>
 2060        /// <param name="conditions">
 2061        /// Optional <see cref="PageBlobRequestConditions"/> to add conditions
 2062        /// on updating the sequence number of this page blob.
 2063        /// </param>
 2064        /// <param name="cancellationToken">
 2065        /// Optional <see cref="CancellationToken"/> to propagate
 2066        /// notifications that the operation should be cancelled.
 2067        /// </param>
 2068        /// <returns>
 2069        /// A <see cref="Response{PageBlobInfo}"/> describing the updated
 2070        /// page blob.
 2071        /// </returns>
 2072        /// <remarks>
 2073        /// A <see cref="RequestFailedException"/> will be thrown if
 2074        /// a failure occurs.
 2075        /// </remarks>
 2076        public virtual Response<PageBlobInfo> UpdateSequenceNumber(
 2077            SequenceNumberAction action,
 2078            long? sequenceNumber = default,
 2079            PageBlobRequestConditions conditions = default,
 2080            CancellationToken cancellationToken = default) =>
 2081            UpdateSequenceNumberInternal(
 2082                action,
 2083                sequenceNumber,
 2084                conditions,
 2085                false, // async
 2086                cancellationToken)
 2087                .EnsureCompleted();
 2088
 2089        /// <summary>
 2090        /// The <see cref="UpdateSequenceNumberAsync"/> operation changes the
 2091        /// sequence number <paramref name="action"/> and <paramref name="sequenceNumber"/>
 2092        /// for this page blob.
 2093        ///
 2094        /// For more information, see
 2095        /// <see href="https://docs.microsoft.com/rest/api/storageservices/set-blob-properties">
 2096        /// Set Blob Properties</see>.
 2097        /// </summary>
 2098        /// <param name="action">
 2099        /// Specifies how the service should modify the blob's sequence number.
 2100        /// <see cref="SequenceNumberAction.Max"/> sets the sequence number to
 2101        /// be the higher of the value included with the request and the value
 2102        /// currently stored for the blob.  <see cref="SequenceNumberAction.Update"/>
 2103        /// sets the sequence number to the <paramref name="sequenceNumber"/>
 2104        /// value.  <see cref="SequenceNumberAction.Increment"/> increments
 2105        /// the value of the sequence number by 1.  If specifying
 2106        /// <see cref="SequenceNumberAction.Increment"/>, do not include the
 2107        /// <paramref name="sequenceNumber"/> because that will throw a
 2108        /// <see cref="RequestFailedException"/>.
 2109        /// </param>
 2110        /// <param name="sequenceNumber">
 2111        /// An updated sequence number of your choosing, if
 2112        /// <paramref name="action"/> is <see cref="SequenceNumberAction.Max"/>
 2113        /// or <see cref="SequenceNumberAction.Update"/>.  The value should
 2114        /// not be provided if <paramref name="action"/> is
 2115        /// <see cref="SequenceNumberAction.Increment"/>.  The sequence number
 2116        /// is a user-controlled property that you can use to track requests
 2117        /// and manage concurrency issues via <see cref="PageBlobRequestConditions"/>.
 2118        /// </param>
 2119        /// <param name="conditions">
 2120        /// Optional <see cref="PageBlobRequestConditions"/> to add conditions
 2121        /// on updating the sequence number of this page blob.
 2122        /// </param>
 2123        /// <param name="cancellationToken">
 2124        /// Optional <see cref="CancellationToken"/> to propagate
 2125        /// notifications that the operation should be cancelled.
 2126        /// </param>
 2127        /// <returns>
 2128        /// A <see cref="Response{PageBlobInfo}"/> describing the updated
 2129        /// page blob.
 2130        /// </returns>
 2131        /// <remarks>
 2132        /// A <see cref="RequestFailedException"/> will be thrown if
 2133        /// a failure occurs.
 2134        /// </remarks>
 2135        public virtual async Task<Response<PageBlobInfo>> UpdateSequenceNumberAsync(
 2136            SequenceNumberAction action,
 2137            long? sequenceNumber = default,
 2138            PageBlobRequestConditions conditions = default,
 2139            CancellationToken cancellationToken = default) =>
 2140            await UpdateSequenceNumberInternal(
 2141                action,
 2142                sequenceNumber,
 2143                conditions,
 2144                true, // async
 2145                cancellationToken)
 2146                .ConfigureAwait(false);
 2147
 2148        /// <summary>
 2149        /// The <see cref="UpdateSequenceNumberInternal"/> operation changes the
 2150        /// sequence number <paramref name="action"/> and <paramref name="sequenceNumber"/>
 2151        /// for this page blob.
 2152        ///
 2153        /// For more information, see
 2154        /// <see href="https://docs.microsoft.com/rest/api/storageservices/set-blob-properties">
 2155        /// Set Blob Properties</see>.
 2156        /// </summary>
 2157        /// <param name="action">
 2158        /// Specifies how the service should modify the blob's sequence number.
 2159        /// <see cref="SequenceNumberAction.Max"/> sets the sequence number to
 2160        /// be the higher of the value included with the request and the value
 2161        /// currently stored for the blob.  <see cref="SequenceNumberAction.Update"/>
 2162        /// sets the sequence number to the <paramref name="sequenceNumber"/>
 2163        /// value.  <see cref="SequenceNumberAction.Increment"/> increments
 2164        /// the value of the sequence number by 1.  If specifying
 2165        /// <see cref="SequenceNumberAction.Increment"/>, do not include the
 2166        /// <paramref name="sequenceNumber"/> because that will throw a
 2167        /// <see cref="RequestFailedException"/>.
 2168        /// </param>
 2169        /// <param name="sequenceNumber">
 2170        /// An updated sequence number of your choosing, if
 2171        /// <paramref name="action"/> is <see cref="SequenceNumberAction.Max"/>
 2172        /// or <see cref="SequenceNumberAction.Update"/>.  The value should
 2173        /// not be provided if <paramref name="action"/> is
 2174        /// <see cref="SequenceNumberAction.Increment"/>.  The sequence number
 2175        /// is a user-controlled property that you can use to track requests
 2176        /// and manage concurrency issues via <see cref="PageBlobRequestConditions"/>.
 2177        /// </param>
 2178        /// <param name="conditions">
 2179        /// Optional <see cref="PageBlobRequestConditions"/> to add conditions
 2180        /// on updating the sequence number of this page blob.
 2181        /// </param>
 2182        /// <param name="async">
 2183        /// Whether to invoke the operation asynchronously.
 2184        /// </param>
 2185        /// <param name="cancellationToken">
 2186        /// Optional <see cref="CancellationToken"/> to propagate
 2187        /// notifications that the operation should be cancelled.
 2188        /// </param>
 2189        /// <returns>
 2190        /// A <see cref="Response{PageBlobInfo}"/> describing the updated
 2191        /// page blob.
 2192        /// </returns>
 2193        /// <remarks>
 2194        /// A <see cref="RequestFailedException"/> will be thrown if
 2195        /// a failure occurs.
 2196        /// </remarks>
 2197        private async Task<Response<PageBlobInfo>> UpdateSequenceNumberInternal(
 2198            SequenceNumberAction action,
 2199            long? sequenceNumber,
 2200            PageBlobRequestConditions conditions,
 2201            bool async,
 2202            CancellationToken cancellationToken)
 2203        {
 2204            using (Pipeline.BeginLoggingScope(nameof(PageBlobClient)))
 2205            {
 2206                Pipeline.LogMethodEnter(
 2207                    nameof(PageBlobClient),
 2208                    message:
 2209                    $"{nameof(Uri)}: {Uri}\n" +
 2210                    $"{nameof(action)}: {action}\n" +
 2211                    $"{nameof(sequenceNumber)}: {sequenceNumber}\n" +
 2212                    $"{nameof(conditions)}: {conditions}");
 2213                try
 2214                {
 2215                    return await BlobRestClient.PageBlob.UpdateSequenceNumberAsync(
 2216                        ClientDiagnostics,
 2217                        Pipeline,
 2218                        Uri,
 2219                        sequenceNumberAction: action,
 2220                        version: Version.ToVersionString(),
 2221                        blobSequenceNumber: sequenceNumber,
 2222                        leaseId: conditions?.LeaseId,
 2223                        ifModifiedSince: conditions?.IfModifiedSince,
 2224                        ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
 2225                        ifMatch: conditions?.IfMatch,
 2226                        ifNoneMatch: conditions?.IfNoneMatch,
 2227                        ifTags: conditions?.TagConditions,
 2228                        operationName: $"{nameof(PageBlobClient)}.{nameof(UpdateSequenceNumber)}",
 2229                        async: async,
 2230                        cancellationToken: cancellationToken)
 2231                        .ConfigureAwait(false);
 2232                }
 2233                catch (Exception ex)
 2234                {
 2235                    Pipeline.LogException(ex);
 2236                    throw;
 2237                }
 2238                finally
 2239                {
 2240                    Pipeline.LogMethodExit(nameof(PageBlobClient));
 2241                }
 2242            }
 2243        }
 2244        #endregion UpdateSequenceNumber
 2245
 2246        #region StartCopyIncremental
 2247        /// <summary>
 2248        /// The <see cref="StartCopyIncremental(Uri, string, PageBlobRequestConditions, CancellationToken)"/>
 2249        /// operation starts copying a snapshot of the sourceUri page blob to
 2250        /// this page blob.  The snapshot is copied such that only the
 2251        /// differential changes between the previously copied snapshot are
 2252        /// transferred to the destination.  The copied snapshots are complete
 2253        /// copies of the original snapshot and can be read or copied from as
 2254        /// usual.  You can check the <see cref="BlobProperties.CopyStatus"/>
 2255        /// returned from the <see cref="BlobBaseClient.GetProperties"/> to
 2256        /// determine if the copy has completed.
 2257        ///
 2258        /// For more information, see
 2259        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/incremental-copy-blob">
 2260        /// Incremental Copy Blob</see> and
 2261        /// <see href="https://docs.microsoft.com/azure/virtual-machines/windows/incremental-snapshots">
 2262        /// Back up Azure unmanaged VM disks with incremental snapshots</see>.
 2263        /// </summary>
 2264        /// <param name="sourceUri">
 2265        /// Specifies the to the source page blob as a <see cref="Uri"/> up to
 2266        /// 2 KB in length.  The source blob must either be public or must be
 2267        /// authenticated via a shared access signature.
 2268        /// </param>
 2269        /// <param name="snapshot">
 2270        /// The name of a snapshot to start copying from
 2271        /// sourceUri.
 2272        /// </param>
 2273        /// <param name="conditions">
 2274        /// Optional <see cref="PageBlobRequestConditions"/> to add
 2275        /// conditions on the incremental copy into this page blob.
 2276        /// </param>
 2277        /// <param name="cancellationToken">
 2278        /// Optional <see cref="CancellationToken"/> to propagate
 2279        /// notifications that the operation should be cancelled.
 2280        /// </param>
 2281        /// <returns>
 2282        /// A <see cref="CopyFromUriOperation"/> referencing the incremental
 2283        /// copy operation.
 2284        /// </returns>
 2285        /// <remarks>
 2286        /// A <see cref="RequestFailedException"/> will be thrown if
 2287        /// a failure occurs.
 2288        ///
 2289        /// The destination of an incremental copy must either not exist, or
 2290        /// must have been created with a previous incremental copy from the
 2291        /// same source blob.  Once created, the destination blob is
 2292        /// permanently associated with the source and may only be used for
 2293        /// incremental copies.
 2294        ///
 2295        /// The <see cref="BlobBaseClient.GetProperties"/>,
 2296        /// <see cref="BlobContainerClient.GetBlobs"/>, and
 2297        /// <see cref="BlobContainerClient.GetBlobsByHierarchy"/>
 2298        /// operations indicate whether the blob is an incremental copy blob
 2299        /// created in this way.  Incremental copy blobs may not be downloaded
 2300        /// directly.  The only supported operations are
 2301        /// <see cref="BlobBaseClient.GetProperties"/>,
 2302        /// <see cref="StartCopyIncremental(Uri, string, PageBlobRequestConditions, CancellationToken)"/>,
 2303        /// and <see cref="BlobBaseClient.Delete"/>.  The copied snapshots may
 2304        /// be read and deleted as usual.
 2305        ///
 2306        /// An incremental copy is performed asynchronously on the service and
 2307        /// must be polled for completion.  You can poll
 2308        /// <see cref="BlobBaseClient.GetProperties"/> and check
 2309        /// <see cref="BlobProperties.CopyStatus"/> to determine when the copy
 2310        /// has completed.  When the copy completes, the destination blob will
 2311        /// contain a new snapshot.  The <see cref="BlobBaseClient.GetProperties"/>
 2312        /// operation returns the snapshot time of the newly created snapshot.
 2313        ///
 2314        /// The first time an incremental copy is performed on a destination
 2315        /// blob, a new blob is created with a snapshot that is fully copied
 2316        /// from the source.  Each subsequent call to <see cref="StartCopyIncremental(Uri, string, PageBlobRequestCondit
 2317        /// will create a new snapshot by copying only the differential
 2318        /// changes from the previously copied snapshot.  The differential
 2319        /// changes are computed on the server by issuing a <see cref="GetPageRanges"/>
 2320        /// call on the source blob snapshot with prevSnapshot set to the most
 2321        /// recently copied snapshot. Therefore, the same restrictions on
 2322        /// <see cref="GetPageRanges"/> apply to
 2323        /// <see cref="StartCopyIncremental(Uri, string, PageBlobRequestConditions, CancellationToken)"/>.
 2324        /// Specifically, snapshots must be copied in ascending order and if
 2325        /// the source blob is recreated using <see cref="UploadPages"/> or
 2326        /// <see cref="BlobBaseClient.StartCopyFromUri(Uri, Metadata, AccessTier?, BlobRequestConditions, BlobRequestCon
 2327        /// then  <see cref="StartCopyIncremental(Uri, string, PageBlobRequestConditions, CancellationToken)"/>
 2328        /// on new snapshots will fail.
 2329        ///
 2330        /// The additional storage space consumed by the copied snapshot is
 2331        /// the size of the differential data transferred during the copy.
 2332        /// This can be determined by performing a
 2333        /// <see cref="GetPageRangesDiff"/>
 2334        /// call on the snapshot to compare it to the previous snapshot.
 2335        /// </remarks>
 2336        public virtual CopyFromUriOperation StartCopyIncremental(
 2337            Uri sourceUri,
 2338            string snapshot,
 2339            PageBlobRequestConditions conditions = default,
 2340            CancellationToken cancellationToken = default)
 2341        {
 2342            Response<BlobCopyInfo> response = StartCopyIncrementalInternal(
 2343                sourceUri,
 2344                snapshot,
 2345                conditions,
 2346                false, // async
 2347                cancellationToken)
 2348                .EnsureCompleted();
 2349            return new CopyFromUriOperation(
 2350                this,
 2351                response.Value.CopyId,
 2352                response.GetRawResponse(),
 2353                cancellationToken);
 2354        }
 2355
 2356        /// <summary>
 2357        /// The <see cref="StartCopyIncrementalAsync(Uri, string, PageBlobRequestConditions, CancellationToken)"/>
 2358        /// operation starts copying a snapshot of the sourceUri page blob to
 2359        /// this page blob.  The snapshot is copied such that only the
 2360        /// differential changes between the previously copied snapshot are
 2361        /// transferred to the destination. The copied snapshots are complete
 2362        /// copies of the original snapshot and can be read or copied from as
 2363        /// usual.  You can check the <see cref="BlobProperties.CopyStatus"/>
 2364        /// returned from the <see cref="BlobBaseClient.GetPropertiesAsync"/>
 2365        /// to determine if thecopy has completed.
 2366        ///
 2367        /// For more information, see
 2368        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/incremental-copy-blob">
 2369        /// Incremental Copy Blob</see> and
 2370        /// <see href="https://docs.microsoft.com/azure/virtual-machines/windows/incremental-snapshots">
 2371        /// Back up Azure unmanaged VM disks with incremental snapshots</see>.
 2372        /// </summary>
 2373        /// <param name="sourceUri">
 2374        /// Specifies the to the source page blob as a <see cref="Uri"/> up to
 2375        /// 2 KB in length.  The source blob must either be public or must be
 2376        /// authenticated via a shared access signature.
 2377        /// </param>
 2378        /// <param name="snapshot">
 2379        /// The name of a snapshot to start copying from
 2380        /// sourceUri.
 2381        /// </param>
 2382        /// <param name="conditions">
 2383        /// Optional <see cref="PageBlobRequestConditions"/> to add
 2384        /// conditions on the incremental copy into this page blob.
 2385        /// </param>
 2386        /// <param name="cancellationToken">
 2387        /// Optional <see cref="CancellationToken"/> to propagate
 2388        /// notifications that the operation should be cancelled.
 2389        /// </param>
 2390        /// <returns>
 2391        /// A <see cref="CopyFromUriOperation"/> describing the
 2392        /// state of the incremental copy operation.
 2393        /// </returns>
 2394        /// <remarks>
 2395        /// A <see cref="RequestFailedException"/> will be thrown if
 2396        /// a failure occurs.
 2397        ///
 2398        /// The destination of an incremental copy must either not exist, or
 2399        /// must have been created with a previous incremental copy from the
 2400        /// same source blob.  Once created, the destination blob is
 2401        /// permanently associated with the source and may only be used for
 2402        /// incremental copies.
 2403        ///
 2404        /// The <see cref="BlobBaseClient.GetPropertiesAsync"/>,
 2405        /// <see cref="BlobContainerClient.GetBlobsAsync"/>, and
 2406        /// <see cref="BlobContainerClient.GetBlobsByHierarchyAsync"/>
 2407        /// operations indicate whether the blob is an incremental copy blob
 2408        /// created in this way.  Incremental copy blobs may not be downloaded
 2409        /// directly.  The only supported operations are
 2410        /// <see cref="BlobBaseClient.GetPropertiesAsync"/>,
 2411        /// <see cref="StartCopyIncrementalAsync(Uri, string, PageBlobRequestConditions, CancellationToken)"/>,
 2412        /// and  <see cref="BlobBaseClient.DeleteAsync"/>.  The copied
 2413        /// snapshots may be read and deleted as usual.
 2414        ///
 2415        /// An incremental copy is performed asynchronously on the service and
 2416        /// must be polled for completion.  You can poll
 2417        /// <see cref="BlobBaseClient.GetPropertiesAsync"/> and check
 2418        /// <see cref="BlobProperties.CopyStatus"/> to determine when the copy
 2419        /// has completed.  When the copy completes, the destination blob will
 2420        /// contain a new snapshot.  The <see cref="BlobBaseClient.GetPropertiesAsync"/>
 2421        /// operation returns the snapshot time of the newly created snapshot.
 2422        ///
 2423        /// The first time an incremental copy is performed on a destination
 2424        /// blob, a new blob is created with a snapshot that is fully copied
 2425        /// from the source.  Each subsequent call to <see cref="StartCopyIncrementalAsync(Uri, string, PageBlobRequestC
 2426        /// will create a new snapshot by copying only the differential
 2427        /// changes from the previously copied snapshot.  The differential
 2428        /// changes are computed on the server by issuing a <see cref="GetPageRangesAsync"/>
 2429        /// call on the source blob snapshot with prevSnapshot set to the most
 2430        /// recently copied snapshot. Therefore, the same restrictions on
 2431        /// <see cref="GetPageRangesAsync"/> apply to
 2432        /// <see cref="StartCopyIncrementalAsync(Uri, string, PageBlobRequestConditions, CancellationToken)"/>.
 2433        /// Specifically, snapshots must be copied in ascending order and if
 2434        /// the source blob is recreated using <see cref="UploadPagesAsync"/> or
 2435        /// <see cref="BlobBaseClient.StartCopyFromUriAsync(Uri, Metadata, AccessTier?, BlobRequestConditions, BlobReque
 2436        /// then <see cref="StartCopyIncrementalAsync(Uri, string, PageBlobRequestConditions, CancellationToken)"/>
 2437        /// on new snapshots will fail.
 2438        ///
 2439        /// The additional storage space consumed by the copied snapshot is
 2440        /// the size of the differential data transferred during the copy.
 2441        /// This can be determined by performing a
 2442        /// <see cref="GetPageRangesDiffAsync"/>
 2443        /// call on the snapshot to compare it to the previous snapshot.
 2444        /// </remarks>
 2445        public virtual async Task<CopyFromUriOperation> StartCopyIncrementalAsync(
 2446            Uri sourceUri,
 2447            string snapshot,
 2448            PageBlobRequestConditions conditions = default,
 2449            CancellationToken cancellationToken = default)
 2450        {
 2451            Response<BlobCopyInfo> response = await StartCopyIncrementalInternal(
 2452                sourceUri,
 2453                snapshot,
 2454                conditions,
 2455                true, // async
 2456                cancellationToken)
 2457                .ConfigureAwait(false);
 2458            return new CopyFromUriOperation(
 2459                this,
 2460                response.Value.CopyId,
 2461                response.GetRawResponse(),
 2462                cancellationToken);
 2463        }
 2464
 2465        /// <summary>
 2466        /// The <see cref="StartCopyIncrementalInternal"/> operation starts
 2467        /// copying a snapshot of the
 2468        /// sourceUri page blob to this page blob.  The
 2469        /// snapshot is copied such that only the differential changes between
 2470        /// the previously copied snapshot are transferred to the destination.
 2471        /// The copied snapshots are complete copies of the original snapshot
 2472        /// and can be read or copied from as usual.  You can check the
 2473        /// <see cref="BlobProperties.CopyStatus"/> returned from the
 2474        /// <see cref="BlobBaseClient.GetPropertiesAsync"/> to determine if the
 2475        /// copy has completed.
 2476        ///
 2477        /// For more information, see
 2478        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/incremental-copy-blob">
 2479        /// Incremental Copy Blob</see> and
 2480        /// <see href="https://docs.microsoft.com/azure/virtual-machines/windows/incremental-snapshots">
 2481        /// Back up Azure unmanaged VM disks with incremental snapshots</see>.
 2482        /// </summary>
 2483        /// <param name="sourceUri">
 2484        /// Specifies the to the source page blob as a <see cref="Uri"/> up to
 2485        /// 2 KB in length.  The source blob must either be public or must be
 2486        /// authenticated via a shared access signature.
 2487        /// </param>
 2488        /// <param name="snapshot">
 2489        /// The name of a snapshot to start copying from
 2490        /// sourceUri.
 2491        /// </param>
 2492        /// <param name="conditions">
 2493        /// Optional <see cref="PageBlobRequestConditions"/> to add
 2494        /// conditions on the incremental copy into this page blob.
 2495        /// </param>
 2496        /// <param name="async">
 2497        /// Whether to invoke the operation asynchronously.
 2498        /// </param>
 2499        /// <param name="cancellationToken">
 2500        /// Optional <see cref="CancellationToken"/> to propagate
 2501        /// notifications that the operation should be cancelled.
 2502        /// </param>
 2503        /// <returns>
 2504        /// A <see cref="Response{BlobCopyInfo}"/> describing the
 2505        /// state of the incremental copy operation.
 2506        /// </returns>
 2507        /// <remarks>
 2508        /// A <see cref="RequestFailedException"/> will be thrown if
 2509        /// a failure occurs.
 2510        ///
 2511        /// The destination of an incremental copy must either not exist, or
 2512        /// must have been created with a previous incremental copy from the
 2513        /// same source blob.  Once created, the destination blob is
 2514        /// permanently associated with the source and may only be used for
 2515        /// incremental copies.
 2516        ///
 2517        /// The <see cref="BlobBaseClient.GetPropertiesAsync"/>,
 2518        /// <see cref="BlobContainerClient.GetBlobsAsync"/>, and
 2519        /// <see cref="BlobContainerClient.GetBlobsByHierarchyAsync"/>
 2520        /// operations indicate whether the blob is an incremental copy blob
 2521        /// created in this way.  Incremental copy blobs may not be downloaded
 2522        /// directly.  The only supported operations are
 2523        /// <see cref="BlobBaseClient.GetPropertiesAsync"/>,
 2524        /// <see cref="StartCopyIncremental(Uri, string, PageBlobRequestConditions, CancellationToken)"/>,
 2525        /// and  <see cref="BlobBaseClient.DeleteAsync"/>.  The copied
 2526        /// snapshots may be read and deleted as usual.
 2527        ///
 2528        /// An incremental copy is performed asynchronously on the service and
 2529        /// must be polled for completion.  You can poll
 2530        /// <see cref="BlobBaseClient.GetPropertiesAsync"/> and check
 2531        /// <see cref="BlobProperties.CopyStatus"/> to determine when the copy
 2532        /// has completed.  When the copy completes, the destination blob will
 2533        /// contain a new snapshot.  The <see cref="BlobBaseClient.GetPropertiesAsync"/>
 2534        /// operation returns the snapshot time of the newly created snapshot.
 2535        ///
 2536        /// The first time an incremental copy is performed on a destination
 2537        /// blob, a new blob is created with a snapshot that is fully copied
 2538        /// from the source.  Each subsequent call to <see cref="StartCopyIncrementalAsync(Uri, string, PageBlobRequestC
 2539        /// will create a new snapshot by copying only the differential
 2540        /// changes from the previously copied snapshot.  The differential
 2541        /// changes are computed on the server by issuing a <see cref="GetPageRangesAsync"/>
 2542        /// call on the source blob snapshot with prevSnapshot set to the most
 2543        /// recently copied snapshot. Therefore, the same restrictions on
 2544        /// <see cref="GetPageRangesAsync"/> apply to
 2545        /// <see cref="StartCopyIncrementalAsync(Uri, string, PageBlobRequestConditions, CancellationToken)"/>.
 2546        /// Specifically, snapshots must be copied in ascending order and if
 2547        /// the source blob is recreated using <see cref="UploadPagesAsync"/>
 2548        /// or  <see cref="BlobBaseClient.StartCopyFromUriAsync(Uri, Metadata, AccessTier?, BlobRequestConditions, BlobR
 2549        /// then <see cref="StartCopyIncrementalAsync(Uri, string, PageBlobRequestConditions, CancellationToken)"/>
 2550        /// on new snapshots will fail.
 2551        ///
 2552        /// The additional storage space consumed by the copied snapshot is
 2553        /// the size of the differential data transferred during the copy.
 2554        /// This can be determined by performing a
 2555        /// <see cref="GetPageRangesDiffInternal"/>
 2556        /// call on the snapshot to compare it to the previous snapshot.
 2557        /// </remarks>
 2558        private async Task<Response<BlobCopyInfo>> StartCopyIncrementalInternal(
 2559            Uri sourceUri,
 2560            string snapshot,
 2561            PageBlobRequestConditions conditions,
 2562            bool async,
 2563            CancellationToken cancellationToken)
 2564        {
 2565            using (Pipeline.BeginLoggingScope(nameof(PageBlobClient)))
 2566            {
 2567                Pipeline.LogMethodEnter(
 2568                    nameof(PageBlobClient),
 2569                    message:
 2570                    $"{nameof(Uri)}: {Uri}\n" +
 2571                    $"{nameof(sourceUri)}: {sourceUri}\n" +
 2572                    $"{nameof(snapshot)}: {snapshot}\n" +
 2573                    $"{nameof(conditions)}: {conditions}");
 2574                try
 2575                {
 2576                    // Create copySource Uri
 2577                    PageBlobClient pageBlobUri = new PageBlobClient(
 2578                        sourceUri,
 2579                        Pipeline,
 2580                        Version,
 2581                        ClientDiagnostics,
 2582                        CustomerProvidedKey,
 2583                        EncryptionScope).WithSnapshot(snapshot);
 2584
 2585                    return await BlobRestClient.PageBlob.CopyIncrementalAsync(
 2586                        ClientDiagnostics,
 2587                        Pipeline,
 2588                        Uri,
 2589                        copySource: pageBlobUri.Uri,
 2590                        version: Version.ToVersionString(),
 2591                        ifModifiedSince: conditions?.IfModifiedSince,
 2592                        ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
 2593                        ifMatch: conditions?.IfMatch,
 2594                        ifNoneMatch: conditions?.IfNoneMatch,
 2595                        ifTags: conditions?.TagConditions,
 2596                        async: async,
 2597                        operationName: $"{nameof(PageBlobClient)}.{nameof(StartCopyIncremental)}",
 2598                        cancellationToken: cancellationToken)
 2599                        .ConfigureAwait(false);
 2600                }
 2601                catch (Exception ex)
 2602                {
 2603                    Pipeline.LogException(ex);
 2604                    throw;
 2605                }
 2606                finally
 2607                {
 2608                    Pipeline.LogMethodExit(nameof(PageBlobClient));
 2609                }
 2610            }
 2611        }
 2612        #endregion StartCopyIncremental
 2613
 2614        #region UploadPagesFromUri
 2615        /// <summary>
 2616        /// The <see cref="UploadPagesFromUri"/> operation writes a range
 2617        /// of pages to a page blob where the contents are read from
 2618        /// sourceUri.
 2619        ///
 2620        /// For more information, see
 2621        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/put-page-from-url">
 2622        /// Put Page From URL</see>.
 2623        /// </summary>
 2624        /// <param name="sourceUri">
 2625        /// Specifies the <see cref="Uri"/> of the source blob.  The value may
 2626        /// be a <see cref="Uri" /> of up to 2 KB in length that specifies a
 2627        /// blob.  The source blob must either be public or must be
 2628        /// authenticated via a shared access signature.  If the source blob
 2629        /// is public, no authentication is required to perform the operation.
 2630        /// </param>
 2631        /// <param name="sourceRange">
 2632        /// Optionally only upload the bytes of the blob in the
 2633        /// sourceUri in the specified range.
 2634        /// </param>
 2635        /// <param name="range">
 2636        /// Specifies the range to be written as a page. Both the start and
 2637        /// end of the range must be specified and can be up to 4MB in size.
 2638        /// Given that pages must be aligned with 512-byte boundaries, the
 2639        /// start of the range must be a modulus of 512 and the end of the
 2640        /// range must be a modulus of 512 – 1.  Examples of valid byte ranges
 2641        /// are 0-511, 512-1023, etc.
 2642        /// </param>
 2643        /// <param name="sourceContentHash">
 2644        /// Optional MD5 hash of the page block content from the
 2645        /// sourceUri.  This hash is used to verify the
 2646        /// integrity of the block during transport of the data from the Uri.
 2647        /// When this hash is specified, the storage service compares the hash
 2648        /// of the content that has arrived from the sourceUri
 2649        /// with this value.  Note that this md5 hash is not stored with the
 2650        /// blob.  If the two hashes do not match, the operation will fail
 2651        /// with a <see cref="RequestFailedException"/>.
 2652        /// </param>
 2653        /// <param name="conditions">
 2654        /// Optional <see cref="AppendBlobRequestConditions"/> to add
 2655        /// conditions on the copying of data to this page blob.
 2656        /// </param>
 2657        /// <param name="sourceConditions">
 2658        /// Optional <see cref="AppendBlobRequestConditions"/> to add
 2659        /// conditions on the copying of data from this source blob.
 2660        /// </param>
 2661        /// <param name="cancellationToken">
 2662        /// Optional <see cref="CancellationToken"/> to propagate
 2663        /// notifications that the operation should be cancelled.
 2664        /// </param>
 2665        /// <returns>
 2666        /// A <see cref="Response{PageInfo}"/> describing the
 2667        /// state of the updated pages.
 2668        /// </returns>
 2669        /// <remarks>
 2670        /// A <see cref="RequestFailedException"/> will be thrown if
 2671        /// a failure occurs.
 2672        /// </remarks>
 2673        public virtual Response<PageInfo> UploadPagesFromUri(
 2674            Uri sourceUri,
 2675            HttpRange sourceRange,
 2676            HttpRange range,
 2677            byte[] sourceContentHash = default,
 2678            PageBlobRequestConditions conditions = default,
 2679            PageBlobRequestConditions sourceConditions = default,
 2680            CancellationToken cancellationToken = default) =>
 2681            UploadPagesFromUriInternal(
 2682                sourceUri,
 2683                sourceRange,
 2684                range,
 2685                sourceContentHash,
 2686                conditions,
 2687                sourceConditions,
 2688                false, // async
 2689                cancellationToken)
 2690                .EnsureCompleted();
 2691
 2692        /// <summary>
 2693        /// The <see cref="UploadPagesFromUriAsync"/> operation writes a range
 2694        /// of pages to a page blob where the contents are read from
 2695        /// sourceUri.
 2696        ///
 2697        /// For more information, see
 2698        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/put-page-from-url">
 2699        /// Put Page From URL</see>.
 2700        /// </summary>
 2701        /// <param name="sourceUri">
 2702        /// Specifies the <see cref="Uri"/> of the source blob.  The value may
 2703        /// be a <see cref="Uri" /> of up to 2 KB in length that specifies a
 2704        /// blob.  The source blob must either be public or must be
 2705        /// authenticated via a shared access signature.  If the source blob
 2706        /// is public, no authentication is required to perform the operation.
 2707        /// </param>
 2708        /// <param name="sourceRange">
 2709        /// Optionally only upload the bytes of the blob in the
 2710        /// sourceUri in the specified range.
 2711        /// </param>
 2712        /// <param name="range">
 2713        /// Specifies the range to be written as a page. Both the start and
 2714        /// end of the range must be specified and can be up to 4MB in size.
 2715        /// Given that pages must be aligned with 512-byte boundaries, the
 2716        /// start of the range must be a modulus of 512 and the end of the
 2717        /// range must be a modulus of 512 – 1.  Examples of valid byte ranges
 2718        /// are 0-511, 512-1023, etc.
 2719        /// </param>
 2720        /// <param name="sourceContentHash">
 2721        /// Optional MD5 hash of the page block content from the
 2722        /// sourceUri.  This hash is used to verify the
 2723        /// integrity of the block during transport of the data from the Uri.
 2724        /// When this hash is specified, the storage service compares the hash
 2725        /// of the content that has arrived from the sourceUri
 2726        /// with this value.  Note that this md5 hash is not stored with the
 2727        /// blob.  If the two hashes do not match, the operation will fail
 2728        /// with a <see cref="RequestFailedException"/>.
 2729        /// </param>
 2730        /// <param name="conditions">
 2731        /// Optional <see cref="AppendBlobRequestConditions"/> to add
 2732        /// conditions on the copying of data to this page blob.
 2733        /// </param>
 2734        /// <param name="sourceConditions">
 2735        /// Optional <see cref="AppendBlobRequestConditions"/> to add
 2736        /// conditions on the copying of data from this source blob.
 2737        /// </param>
 2738        /// <param name="cancellationToken">
 2739        /// Optional <see cref="CancellationToken"/> to propagate
 2740        /// notifications that the operation should be cancelled.
 2741        /// </param>
 2742        /// <returns>
 2743        /// A <see cref="Response{PageInfo}"/> describing the
 2744        /// state of the updated pages.
 2745        /// </returns>
 2746        /// <remarks>
 2747        /// A <see cref="RequestFailedException"/> will be thrown if
 2748        /// a failure occurs.
 2749        /// </remarks>
 2750        public virtual async Task<Response<PageInfo>> UploadPagesFromUriAsync(
 2751            Uri sourceUri,
 2752            HttpRange sourceRange,
 2753            HttpRange range,
 2754            byte[] sourceContentHash = default,
 2755            PageBlobRequestConditions conditions = default,
 2756            PageBlobRequestConditions sourceConditions = default,
 2757            CancellationToken cancellationToken = default) =>
 2758            await UploadPagesFromUriInternal(
 2759                sourceUri,
 2760                sourceRange,
 2761                range,
 2762                sourceContentHash,
 2763                conditions,
 2764                sourceConditions,
 2765                true, // async
 2766                cancellationToken)
 2767                .ConfigureAwait(false);
 2768
 2769        /// <summary>
 2770        /// The <see cref="UploadPagesFromUriInternal"/> operation writes a
 2771        /// range of pages to a page blob where the contents are read from
 2772        /// sourceUri.
 2773        ///
 2774        /// For more information, see
 2775        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/put-page-from-url">
 2776        /// Put Page From URL</see>.
 2777        /// </summary>
 2778        /// <param name="sourceUri">
 2779        /// Specifies the <see cref="Uri"/> of the source blob.  The value may
 2780        /// be a <see cref="Uri" /> of up to 2 KB in length that specifies a
 2781        /// blob.  The source blob must either be public or must be
 2782        /// authenticated via a shared access signature.  If the source blob
 2783        /// is public, no authentication is required to perform the operation.
 2784        /// </param>
 2785        /// <param name="sourceRange">
 2786        /// Optionally only upload the bytes of the blob in the
 2787        /// sourceUri in the specified range.
 2788        /// </param>
 2789        /// <param name="range">
 2790        /// Specifies the range to be written as a page. Both the start and
 2791        /// end of the range must be specified and can be up to 4MB in size.
 2792        /// Given that pages must be aligned with 512-byte boundaries, the
 2793        /// start of the range must be a modulus of 512 and the end of the
 2794        /// range must be a modulus of 512 – 1.  Examples of valid byte ranges
 2795        /// are 0-511, 512-1023, etc.
 2796        /// </param>
 2797        /// <param name="sourceContentHash">
 2798        /// Optional MD5 hash of the page block content from the
 2799        /// sourceUri.  This hash is used to verify the
 2800        /// integrity of the block during transport of the data from the Uri.
 2801        /// When this hash is specified, the storage service compares the hash
 2802        /// of the content that has arrived from the sourceUri
 2803        /// with this value.  Note that this md5 hash is not stored with the
 2804        /// blob.  If the two hashes do not match, the operation will fail
 2805        /// with a <see cref="RequestFailedException"/>.
 2806        /// </param>
 2807        /// <param name="conditions">
 2808        /// Optional <see cref="AppendBlobRequestConditions"/> to add
 2809        /// conditions on the copying of data to this page blob.
 2810        /// </param>
 2811        /// <param name="sourceConditions">
 2812        /// Optional <see cref="AppendBlobRequestConditions"/> to add
 2813        /// conditions on the copying of data from this source blob.
 2814        /// </param>
 2815        /// <param name="async">
 2816        /// Whether to invoke the operation asynchronously.
 2817        /// </param>
 2818        /// <param name="cancellationToken">
 2819        /// Optional <see cref="CancellationToken"/> to propagate
 2820        /// notifications that the operation should be cancelled.
 2821        /// </param>
 2822        /// <returns>
 2823        /// A <see cref="Response{PageInfo}"/> describing the
 2824        /// state of the updated pages.
 2825        /// </returns>
 2826        /// <remarks>
 2827        /// A <see cref="RequestFailedException"/> will be thrown if
 2828        /// a failure occurs.
 2829        /// </remarks>
 2830        private async Task<Response<PageInfo>> UploadPagesFromUriInternal(
 2831            Uri sourceUri,
 2832            HttpRange sourceRange,
 2833            HttpRange range,
 2834            byte[] sourceContentHash,
 2835            PageBlobRequestConditions conditions,
 2836            PageBlobRequestConditions sourceConditions,
 2837            bool async,
 2838            CancellationToken cancellationToken)
 2839        {
 2840            using (Pipeline.BeginLoggingScope(nameof(PageBlobClient)))
 2841            {
 2842                Pipeline.LogMethodEnter(
 2843                    nameof(PageBlobClient),
 2844                    message:
 2845                    $"{nameof(Uri)}: {Uri}\n" +
 2846                    $"{nameof(sourceUri)}: {sourceUri}");
 2847                try
 2848                {
 2849                    return await BlobRestClient.PageBlob.UploadPagesFromUriAsync(
 2850                        ClientDiagnostics,
 2851                        Pipeline,
 2852                        Uri,
 2853                        sourceUri: sourceUri,
 2854                        sourceRange: sourceRange.ToString(),
 2855                        sourceContentHash: sourceContentHash,
 2856                        contentLength: default,
 2857                        version: Version.ToVersionString(),
 2858                        timeout: default,
 2859                        encryptionKey: CustomerProvidedKey?.EncryptionKey,
 2860                        encryptionKeySha256: CustomerProvidedKey?.EncryptionKeyHash,
 2861                        encryptionAlgorithm: CustomerProvidedKey?.EncryptionAlgorithm,
 2862                        encryptionScope: EncryptionScope,
 2863                        range: range.ToString(),
 2864                        leaseId: conditions?.LeaseId,
 2865                        ifSequenceNumberLessThanOrEqualTo: conditions?.IfSequenceNumberLessThanOrEqual,
 2866                        ifSequenceNumberLessThan: conditions?.IfSequenceNumberLessThan,
 2867                        ifSequenceNumberEqualTo: conditions?.IfSequenceNumberEqual,
 2868                        ifModifiedSince: conditions?.IfModifiedSince,
 2869                        ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
 2870                        ifMatch: conditions?.IfMatch,
 2871                        ifNoneMatch: conditions?.IfNoneMatch,
 2872                        ifTags: conditions?.TagConditions,
 2873                        sourceIfModifiedSince: sourceConditions?.IfModifiedSince,
 2874                        sourceIfUnmodifiedSince: sourceConditions?.IfUnmodifiedSince,
 2875                        sourceIfMatch: sourceConditions?.IfMatch,
 2876                        sourceIfNoneMatch: sourceConditions?.IfNoneMatch,
 2877                        async: async,
 2878                        operationName: $"{nameof(PageBlobClient)}.{nameof(UploadPagesFromUri)}",
 2879                        cancellationToken: cancellationToken)
 2880                        .ConfigureAwait(false);
 2881                }
 2882                catch (Exception ex)
 2883                {
 2884                    Pipeline.LogException(ex);
 2885                    throw;
 2886                }
 2887                finally
 2888                {
 2889                    Pipeline.LogMethodExit(nameof(PageBlobClient));
 2890                }
 2891            }
 2892        }
 2893        #endregion UploadPagesFromUri
 2894    }
 2895
 2896    /// <summary>
 2897    /// Add easy to discover methods to <see cref="BlobContainerClient"/> for
 2898    /// creating <see cref="PageBlobClient"/> instances.
 2899    /// </summary>
 2900    public static partial class SpecializedBlobExtensions
 2901    {
 2902        /// <summary>
 2903        /// Create a new <see cref="PageBlobClient"/> object by
 2904        /// concatenating <paramref name="blobName"/> to
 2905        /// the end of the <paramref name="client"/>'s
 2906        /// <see cref="BlobContainerClient.Uri"/>. The new
 2907        /// <see cref="PageBlobClient"/>
 2908        /// uses the same request policy pipeline as the
 2909        /// <see cref="BlobContainerClient"/>.
 2910        /// </summary>
 2911        /// <param name="client">The <see cref="BlobContainerClient"/>.</param>
 2912        /// <param name="blobName">The name of the page blob.</param>
 2913        /// <returns>A new <see cref="PageBlobClient"/> instance.</returns>
 2914        public static PageBlobClient GetPageBlobClient(
 2915            this BlobContainerClient client,
 2916            string blobName)
 2917        {
 10402918            if (client.ClientSideEncryption != default)
 2919            {
 02920                throw Errors.ClientSideEncryption.TypeNotSupported(typeof(PageBlobClient));
 2921            }
 2922
 10402923            BlobUriBuilder blobUriBuilder = new BlobUriBuilder(client.Uri)
 10402924            {
 10402925                BlobName = blobName
 10402926            };
 2927
 10402928            return new PageBlobClient(
 10402929                blobUriBuilder.ToUri(),
 10402930                client.Pipeline,
 10402931                client.Version,
 10402932                client.ClientDiagnostics,
 10402933                client.CustomerProvidedKey,
 10402934                client.EncryptionScope);
 2935        }
 2936    }
 2937}