< Summary

Class:Azure.Storage.Blobs.Specialized.AppendBlobClient
Assembly:Azure.Storage.Blobs
File(s):C:\Git\azure-sdk-for-net\sdk\storage\Azure.Storage.Blobs\src\AppendBlobClient.cs
Covered lines:269
Uncovered lines:24
Coverable lines:293
Total lines:1436
Line coverage:91.8% (269 of 293)
Covered branches:107
Total branches:134
Branch coverage:79.8% (107 of 134)

Metrics

MethodCyclomatic complexity Line coverage Branch coverage
get_AppendBlobMaxAppendBlockBytes()-0%100%
get_AppendBlobMaxBlocks()-0%100%
.ctor()-100%100%
.ctor(...)-0%100%
.ctor(...)-100%100%
.ctor(...)-100%100%
.ctor(...)-0%100%
.ctor(...)-33.33%100%
.ctor(...)-100%100%
AssertNoClientSideEncryption(...)-66.67%75%
WithSnapshot(...)-100%100%
WithVersion(...)-100%100%
Create(...)-100%50%
CreateAsync()-100%50%
Create(...)-100%100%
CreateAsync()-100%100%
CreateIfNotExists(...)-0%0%
CreateIfNotExistsAsync()-0%0%
CreateIfNotExists(...)-100%100%
CreateIfNotExistsAsync()-100%100%
CreateIfNotExistsInternal()-100%100%
CreateInternal()-100%82.35%
AppendBlock(...)-100%100%
AppendBlockAsync()-100%100%
AppendBlockInternal()-100%100%
AppendBlockFromUri(...)-100%100%
AppendBlockFromUriAsync()-100%100%
AppendBlockFromUriInternal()-100%100%
Seal(...)-100%100%
SealAsync()-100%100%
SealInternal()-100%100%

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>
 041        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>
 046        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>
 74453        protected AppendBlobClient()
 54        {
 74455        }
 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)
 075            : base(connectionString, blobContainerName, blobName)
 76        {
 077        }
 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
 20102            : base(connectionString, blobContainerName, blobName, options)
 103        {
 20104            AssertNoClientSideEncryption(options);
 20105        }
 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)
 16123            : base(blobUri, options)
 124        {
 12125            AssertNoClientSideEncryption(options);
 12126        }
 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)
 0147            : base(blobUri, credential, options)
 148        {
 0149            AssertNoClientSideEncryption(options);
 0150        }
 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)
 4171            : base(blobUri, credential, options)
 172        {
 0173            AssertNoClientSideEncryption(options);
 0174        }
 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)
 828202            : base(
 828203                  blobUri,
 828204                  pipeline,
 828205                  version,
 828206                  clientDiagnostics,
 828207                  customerProvidedKey,
 828208                  clientSideEncryption: default,
 828209                  encryptionScope)
 210        {
 828211        }
 212
 213        private static void AssertNoClientSideEncryption(BlobClientOptions options)
 214        {
 32215            if (options?._clientSideEncryptionOptions != default)
 216            {
 0217                throw Errors.ClientSideEncryption.TypeNotSupported(typeof(AppendBlobClient));
 218            }
 32219        }
 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        {
 4239            BlobUriBuilder blobUriBuilder = new BlobUriBuilder(Uri)
 4240            {
 4241                Snapshot = snapshot
 4242            };
 243
 4244            return new AppendBlobClient(
 4245                blobUriBuilder.ToUri(),
 4246                Pipeline,
 4247                Version,
 4248                ClientDiagnostics,
 4249                CustomerProvidedKey,
 4250                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        {
 72267            BlobUriBuilder blobUriBuilder = new BlobUriBuilder(Uri)
 72268            {
 72269                VersionId = versionId
 72270            };
 271
 72272            return new AppendBlobClient(
 72273                blobUriBuilder.ToUri(),
 72274                Pipeline,
 72275                Version,
 72276                ClientDiagnostics,
 72277                CustomerProvidedKey,
 72278                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) =>
 14306            CreateInternal(
 14307                httpHeaders: options?.HttpHeaders,
 14308                metadata: options?.Metadata,
 14309                tags: options?.Tags,
 14310                conditions: options?.Conditions,
 14311                async: false,
 14312                cancellationToken: cancellationToken)
 14313            .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) =>
 14339            await CreateInternal(
 14340                httpHeaders: options?.HttpHeaders,
 14341                metadata: options?.Metadata,
 14342                tags: options?.Tags,
 14343                conditions: options?.Conditions,
 14344                async: true,
 14345                cancellationToken: cancellationToken)
 14346            .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) =>
 332387            CreateInternal(
 332388                httpHeaders,
 332389                metadata,
 332390                default,
 332391                conditions,
 332392                false, // async
 332393                cancellationToken)
 332394                .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) =>
 344435            await CreateInternal(
 344436                httpHeaders,
 344437                metadata,
 344438                default,
 344439                conditions,
 344440                true, // async
 344441                cancellationToken)
 344442                .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) =>
 0472            CreateIfNotExistsInternal(
 0473                options?.HttpHeaders,
 0474                options?.Metadata,
 0475                options?.Tags,
 0476                async: false,
 0477                cancellationToken: cancellationToken)
 0478            .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) =>
 0508            await CreateIfNotExistsInternal(
 0509                options?.HttpHeaders,
 0510                options?.Metadata,
 0511                options?.Tags,
 0512                async: true,
 0513                cancellationToken: cancellationToken)
 0514            .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) =>
 6550            CreateIfNotExistsInternal(
 6551                httpHeaders,
 6552                metadata,
 6553                default,
 6554                false, // async
 6555                cancellationToken)
 6556                .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) =>
 6592            await CreateIfNotExistsInternal(
 6593                httpHeaders,
 6594                metadata,
 6595                default,
 6596                true, // async
 6597                cancellationToken)
 6598                .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        {
 12642            using (Pipeline.BeginLoggingScope(nameof(AppendBlobClient)))
 643            {
 644                Pipeline.LogMethodEnter(
 645                    nameof(AppendBlobClient),
 646                    message:
 647                    $"{nameof(Uri)}: {Uri}\n" +
 648                    $"{nameof(httpHeaders)}: {httpHeaders}");
 12649                var conditions = new AppendBlobRequestConditions { IfNoneMatch = new ETag(Constants.Wildcard) };
 650                try
 651                {
 12652                    Response<BlobContentInfo> response = await CreateInternal(
 12653                        httpHeaders,
 12654                        metadata,
 12655                        tags,
 12656                        conditions,
 12657                        async,
 12658                        cancellationToken,
 12659                        $"{nameof(AppendBlobClient)}.{nameof(CreateIfNotExists)}")
 12660                        .ConfigureAwait(false);
 661
 4662                    return response;
 663                }
 664                catch (RequestFailedException storageRequestFailedException)
 8665                when (storageRequestFailedException.ErrorCode == BlobErrorCode.BlobAlreadyExists)
 666                {
 4667                    return default;
 668                }
 4669                catch (Exception ex)
 670                {
 671                    Pipeline.LogException(ex);
 4672                    throw;
 673                }
 674                finally
 675                {
 676                    Pipeline.LogMethodExit(nameof(AppendBlobClient));
 677                }
 678            }
 8679        }
 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        {
 716732            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                {
 716742                    return await BlobRestClient.AppendBlob.CreateAsync(
 716743                        ClientDiagnostics,
 716744                        Pipeline,
 716745                        Uri,
 716746                        contentLength: default,
 716747                        version: Version.ToVersionString(),
 716748                        blobContentType: httpHeaders?.ContentType,
 716749                        blobContentEncoding: httpHeaders?.ContentEncoding,
 716750                        blobContentLanguage: httpHeaders?.ContentLanguage,
 716751                        blobContentHash: httpHeaders?.ContentHash,
 716752                        blobCacheControl: httpHeaders?.CacheControl,
 716753                        metadata: metadata,
 716754                        leaseId: conditions?.LeaseId,
 716755                        blobContentDisposition: httpHeaders?.ContentDisposition,
 716756                        encryptionKey: CustomerProvidedKey?.EncryptionKey,
 716757                        encryptionKeySha256: CustomerProvidedKey?.EncryptionKeyHash,
 716758                        encryptionAlgorithm: CustomerProvidedKey?.EncryptionAlgorithm,
 716759                        encryptionScope: EncryptionScope,
 716760                        ifModifiedSince: conditions?.IfModifiedSince,
 716761                        ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
 716762                        ifMatch: conditions?.IfMatch,
 716763                        ifNoneMatch: conditions?.IfNoneMatch,
 716764                        ifTags: conditions?.TagConditions,
 716765                        blobTagsString: tags?.ToTagsString(),
 716766                        async: async,
 716767                        operationName: operationName ?? $"{nameof(AppendBlobClient)}.{nameof(Create)}",
 716768                        cancellationToken: cancellationToken)
 716769                        .ConfigureAwait(false);
 770                }
 36771                catch (Exception ex)
 772                {
 773                    Pipeline.LogException(ex);
 36774                    throw;
 775                }
 776                finally
 777                {
 778                    Pipeline.LogMethodExit(nameof(AppendBlobClient));
 779                }
 780            }
 680781        }
 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) =>
 110834            AppendBlockInternal(
 110835                content,
 110836                transactionalContentHash,
 110837                conditions,
 110838                progressHandler,
 110839                false, // async
 110840                cancellationToken)
 110841                .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) =>
 118892            await AppendBlockInternal(
 118893                content,
 118894                transactionalContentHash,
 118895                conditions,
 118896                progressHandler,
 118897                true, // async
 118898                cancellationToken)
 118899                .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        {
 228955            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                {
 228964                    BlobErrors.VerifyHttpsCustomerProvidedKey(Uri, CustomerProvidedKey);
 965
 228966                    content = content?.WithNoDispose().WithProgress(progressHandler);
 228967                    return await BlobRestClient.AppendBlob.AppendBlockAsync(
 228968                        ClientDiagnostics,
 228969                        Pipeline,
 228970                        Uri,
 228971                        body: content,
 228972                        contentLength: content?.Length ?? 0,
 228973                        version: Version.ToVersionString(),
 228974                        transactionalContentHash: transactionalContentHash,
 228975                        leaseId: conditions?.LeaseId,
 228976                        maxSize: conditions?.IfMaxSizeLessThanOrEqual,
 228977                        encryptionKey: CustomerProvidedKey?.EncryptionKey,
 228978                        encryptionKeySha256: CustomerProvidedKey?.EncryptionKeyHash,
 228979                        encryptionAlgorithm: CustomerProvidedKey?.EncryptionAlgorithm,
 228980                        encryptionScope: EncryptionScope,
 228981                        appendPosition: conditions?.IfAppendPositionEqual,
 228982                        ifModifiedSince: conditions?.IfModifiedSince,
 228983                        ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
 228984                        ifMatch: conditions?.IfMatch,
 228985                        ifNoneMatch: conditions?.IfNoneMatch,
 228986                        ifTags: conditions?.TagConditions,
 228987                        async: async,
 228988                        operationName: "AppendBlobClient.AppendBlock",
 228989                        cancellationToken: cancellationToken).ConfigureAwait(false);
 990                }
 44991                catch (Exception ex)
 992                {
 993                    Pipeline.LogException(ex);
 44994                    throw;
 995                }
 996                finally
 997                {
 998                    Pipeline.LogMethodExit(nameof(AppendBlobClient));
 999                }
 1000            }
 1841001        }
 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) =>
 641066            AppendBlockFromUriInternal(
 641067                sourceUri,
 641068                sourceRange,
 641069                sourceContentHash,
 641070                conditions,
 641071                sourceConditions,
 641072                false, // async
 641073                cancellationToken)
 641074                .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) =>
 641137            await AppendBlockFromUriInternal(
 641138                sourceUri,
 641139                sourceRange,
 641140                sourceContentHash,
 641141                conditions,
 641142                sourceConditions,
 641143                true,  // async
 641144                cancellationToken)
 641145                .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        {
 1281213            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                {
 1281223                    return await BlobRestClient.AppendBlob.AppendBlockFromUriAsync(
 1281224                        ClientDiagnostics,
 1281225                        Pipeline,
 1281226                        Uri,
 1281227                        sourceUri: sourceUri,
 1281228                        sourceRange: sourceRange.ToString(),
 1281229                        sourceContentHash: sourceContentHash,
 1281230                        contentLength: default,
 1281231                        version: Version.ToVersionString(),
 1281232                        encryptionKey: CustomerProvidedKey?.EncryptionKey,
 1281233                        encryptionKeySha256: CustomerProvidedKey?.EncryptionKeyHash,
 1281234                        encryptionAlgorithm: CustomerProvidedKey?.EncryptionAlgorithm,
 1281235                        encryptionScope: EncryptionScope,
 1281236                        leaseId: conditions?.LeaseId,
 1281237                        maxSize: conditions?.IfMaxSizeLessThanOrEqual,
 1281238                        appendPosition: conditions?.IfAppendPositionEqual,
 1281239                        ifModifiedSince: conditions?.IfModifiedSince,
 1281240                        ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
 1281241                        ifMatch: conditions?.IfMatch,
 1281242                        ifNoneMatch: conditions?.IfNoneMatch,
 1281243                        ifTags: conditions?.TagConditions,
 1281244                        sourceIfModifiedSince: sourceConditions?.IfModifiedSince,
 1281245                        sourceIfUnmodifiedSince: sourceConditions?.IfUnmodifiedSince,
 1281246                        sourceIfMatch: sourceConditions?.IfMatch,
 1281247                        sourceIfNoneMatch: sourceConditions?.IfNoneMatch,
 1281248                        async: async,
 1281249                        operationName: "AppendBlobClient.AppendBlockFromUri",
 1281250                        cancellationToken: cancellationToken)
 1281251                        .ConfigureAwait(false);
 1252                }
 521253                catch (Exception ex)
 1254                {
 1255                    Pipeline.LogException(ex);
 521256                    throw;
 1257                }
 1258                finally
 1259                {
 1260                    Pipeline.LogMethodExit(nameof(AppendBlobClient));
 1261                }
 1262            }
 761263        }
 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)
 301290            => SealInternal(
 301291                conditions,
 301292                async: false,
 301293                cancellationToken: cancellationToken)
 301294                .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)
 301319            => await SealInternal(
 301320                conditions,
 301321                async: true,
 301322                cancellationToken: cancellationToken)
 301323                .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        {
 601353            using (Pipeline.BeginLoggingScope(nameof(AppendBlobClient)))
 1354            {
 1355                try
 1356                {
 601357                    Response<AppendBlobSealInternal> response = await BlobRestClient.AppendBlob.SealAsync(
 601358                        ClientDiagnostics,
 601359                        Pipeline,
 601360                        Uri,
 601361                        Version.ToVersionString(),
 601362                        leaseId: conditions?.LeaseId,
 601363                        ifModifiedSince: conditions?.IfModifiedSince,
 601364                        ifUnmodifiedSince: conditions?.IfUnmodifiedSince,
 601365                        ifMatch: conditions?.IfMatch,
 601366                        ifNoneMatch: conditions?.IfNoneMatch,
 601367                        appendPosition: conditions?.IfAppendPositionEqual,
 601368                        async: async,
 601369                        operationName: $"{nameof(AppendBlobClient)}.{nameof(Seal)}",
 601370                        cancellationToken: cancellationToken)
 601371                        .ConfigureAwait(false);
 1372
 321373                    return Response.FromValue(
 321374                        new BlobInfo
 321375                        {
 321376                            ETag = response.Value.ETag,
 321377                            LastModified = response.Value.LastModified
 321378                        },
 321379                        response.GetRawResponse());
 1380                }
 281381                catch (Exception ex)
 1382                {
 1383                    Pipeline.LogException(ex);
 281384                    throw;
 1385                }
 1386                finally
 1387                {
 1388                    Pipeline.LogMethodExit(nameof(AppendBlobClient));
 1389                }
 1390            }
 321391        }
 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        {
 1417            if (client.ClientSideEncryption != default)
 1418            {
 1419                throw Errors.ClientSideEncryption.TypeNotSupported(typeof(AppendBlobClient));
 1420            }
 1421
 1422            BlobUriBuilder blobUriBuilder = new BlobUriBuilder(client.Uri)
 1423            {
 1424                BlobName = blobName
 1425            };
 1426
 1427            return new AppendBlobClient(
 1428                blobUriBuilder.ToUri(),
 1429                client.Pipeline,
 1430                client.Version,
 1431                client.ClientDiagnostics,
 1432                client.CustomerProvidedKey,
 1433                client.EncryptionScope);
 1434        }
 1435    }
 1436}