< Summary

Class:Azure.Storage.Queues.Specialized.SpecializedQueueExtensions
Assembly:Azure.Storage.Queues
File(s):C:\Git\azure-sdk-for-net\sdk\storage\Azure.Storage.Queues\src\QueueClient.cs
Covered lines:0
Uncovered lines:6
Coverable lines:6
Total lines:2276
Line coverage:0% (0 of 6)
Covered branches:0
Total branches:0

Metrics

MethodCyclomatic complexity Line coverage Branch coverage
WithClientSideEncryptionOptions(...)-0%100%

File(s)

C:\Git\azure-sdk-for-net\sdk\storage\Azure.Storage.Queues\src\QueueClient.cs

#LineLine coverage
 1// Copyright (c) Microsoft Corporation. All rights reserved.
 2// Licensed under the MIT License.
 3
 4using System;
 5using System.Collections.Generic;
 6using System.Globalization;
 7using System.Linq;
 8using System.Threading;
 9using System.Threading.Tasks;
 10using Azure.Core;
 11using Azure.Core.Pipeline;
 12using Azure.Storage.Cryptography;
 13using Azure.Storage.Queues.Models;
 14using Azure.Storage.Queues.Specialized;
 15using Metadata = System.Collections.Generic.IDictionary<string, string>;
 16
 17#pragma warning disable SA1402  // File may only contain a single type
 18
 19namespace Azure.Storage.Queues
 20{
 21    /// <summary>
 22    /// A QueueClient represents a URI to the Azure Storage Queue service allowing you to manipulate a queue.
 23    /// </summary>
 24    public class QueueClient
 25    {
 26        /// <summary>
 27        /// The Uri endpoint used by the object.
 28        /// </summary>
 29        private readonly Uri _uri;
 30
 31        /// <summary>
 32        /// Gets the Uri endpoint used by the object.
 33        /// </summary>
 34        public virtual Uri Uri => _uri;
 35
 36        /// <summary>
 37        /// The Uri endpoint used by the object's messages.
 38        /// </summary>
 39        private readonly Uri _messagesUri;
 40
 41        /// <summary>
 42        /// Gets the Uri endpoint used by the object's messages.
 43        /// </summary>
 44        protected virtual Uri MessagesUri => _messagesUri;
 45
 46        /// <summary>
 47        /// The HttpPipeline used to send REST requests.
 48        /// </summary>
 49        private readonly HttpPipeline _pipeline;
 50
 51        /// <summary>
 52        /// Gets the HttpPipeline used to send REST requests.
 53        /// </summary>
 54        internal virtual HttpPipeline Pipeline => _pipeline;
 55
 56        /// <summary>
 57        /// The version of the service to use when sending requests.
 58        /// </summary>
 59        private readonly QueueClientOptions.ServiceVersion _version;
 60
 61        /// <summary>
 62        /// The version of the service to use when sending requests.
 63        /// </summary>
 64        internal virtual QueueClientOptions.ServiceVersion Version => _version;
 65
 66        /// <summary>
 67        /// The <see cref="ClientDiagnostics"/> instance used to create diagnostic scopes
 68        /// every request.
 69        /// </summary>
 70        private readonly ClientDiagnostics _clientDiagnostics;
 71
 72        /// <summary>
 73        /// The <see cref="ClientDiagnostics"/> instance used to create diagnostic scopes
 74        /// every request.
 75        /// </summary>
 76        internal virtual ClientDiagnostics ClientDiagnostics => _clientDiagnostics;
 77
 78        /// <summary>
 79        /// The <see cref="QueueClientSideEncryptionOptions"/> to be used when sending/receiving requests.
 80        /// </summary>
 81        private readonly QueueClientSideEncryptionOptions _clientSideEncryption;
 82
 83        /// <summary>
 84        /// The <see cref="QueueClientSideEncryptionOptions"/> to be used when sending/receiving requests.
 85        /// </summary>
 86        internal virtual QueueClientSideEncryptionOptions ClientSideEncryption => _clientSideEncryption;
 87
 88        internal bool UsingClientSideEncryption => ClientSideEncryption != default;
 89
 90        /// <summary>
 91        /// QueueMaxMessagesPeek indicates the maximum number of messages
 92        /// you can retrieve with each call to Peek.
 93        /// </summary>
 94        public virtual int MaxPeekableMessages => Constants.Queue.MaxMessagesDequeue;
 95
 96        /// <summary>
 97        /// Gets the maximum number of bytes allowed for a message's UTF-8 text.
 98        /// </summary>
 99        public virtual int MessageMaxBytes => Constants.Queue.QueueMessageMaxBytes;
 100
 101        /// <summary>
 102        /// The Storage account name corresponding to the queue client.
 103        /// </summary>
 104        private string _accountName;
 105
 106        /// <summary>
 107        /// Gets the Storage account name corresponding to the queue client.
 108        /// </summary>
 109        public virtual string AccountName
 110        {
 111            get
 112            {
 113                SetNameFieldsIfNull();
 114                return _accountName;
 115            }
 116        }
 117
 118        /// <summary>
 119        /// The name of the queue.
 120        /// </summary>
 121        private string _name;
 122
 123        /// <summary>
 124        /// Gets the name of the queue.
 125        /// </summary>
 126        public virtual string Name
 127        {
 128            get
 129            {
 130                SetNameFieldsIfNull();
 131                return _name;
 132            }
 133        }
 134
 135        #region ctors
 136        /// <summary>
 137        /// Initializes a new instance of the <see cref="QueueClient"/>
 138        /// class for mocking.
 139        /// </summary>
 140        protected QueueClient()
 141        {
 142        }
 143
 144        /// <summary>
 145        /// Initializes a new instance of the <see cref="QueueClient"/>
 146        /// class.
 147        /// </summary>
 148        /// <param name="connectionString">
 149        /// A connection string includes the authentication information
 150        /// required for your application to access data in an Azure Storage
 151        /// account at runtime.
 152        ///
 153        /// For more information, see
 154        /// <see href="https://docs.microsoft.com/azure/storage/common/storage-configure-connection-string">
 155        /// Configure Azure Storage connection strings</see>.
 156        /// </param>
 157        /// <param name="queueName">
 158        /// The name of the queue in the storage account to reference.
 159        /// </param>
 160        public QueueClient(string connectionString, string queueName)
 161            : this(connectionString, queueName, null)
 162        {
 163        }
 164
 165        /// <summary>
 166        /// Initializes a new instance of the <see cref="QueueClient"/>
 167        /// class.
 168        /// </summary>
 169        /// <param name="connectionString">
 170        /// A connection string includes the authentication information
 171        /// required for your application to access data in an Azure Storage
 172        /// account at runtime.
 173        ///
 174        /// For more information, see
 175        /// <see href="https://docs.microsoft.com/azure/storage/common/storage-configure-connection-string">
 176        /// Configure Azure Storage connection strings</see>.
 177        /// </param>
 178        /// <param name="queueName">
 179        /// The name of the queue in the storage account to reference.
 180        /// </param>
 181        /// <param name="options">
 182        /// Optional client options that define the transport pipeline
 183        /// policies for authentication, retries, etc., that are applied to
 184        /// every request.
 185        /// </param>
 186        public QueueClient(string connectionString, string queueName, QueueClientOptions options)
 187        {
 188            var conn = StorageConnectionString.Parse(connectionString);
 189            var builder =
 190                new QueueUriBuilder(conn.QueueEndpoint)
 191                {
 192                    QueueName = queueName
 193                };
 194            _uri = builder.ToUri();
 195            _messagesUri = _uri.AppendToPath(Constants.Queue.MessagesUri);
 196            options ??= new QueueClientOptions();
 197            _pipeline = options.Build(conn.Credentials);
 198            _version = options.Version;
 199            _clientDiagnostics = new ClientDiagnostics(options);
 200            _clientSideEncryption = QueueClientSideEncryptionOptions.CloneFrom(options._clientSideEncryptionOptions);
 201        }
 202
 203        /// <summary>
 204        /// Initializes a new instance of the <see cref="QueueClient"/>
 205        /// class.
 206        /// </summary>
 207        /// <param name="queueUri">
 208        /// A <see cref="Uri"/> referencing the queue that includes the
 209        /// name of the account, and the name of the queue.
 210        /// This is likely to be similar to "https://{account_name}.queue.core.windows.net/{queue_name}".
 211        /// </param>
 212        /// <param name="options">
 213        /// Optional client options that define the transport pipeline
 214        /// policies for authentication, retries, etc., that are applied to
 215        /// every request.
 216        /// </param>
 217        public QueueClient(Uri queueUri, QueueClientOptions options = default)
 218            : this(queueUri, (HttpPipelinePolicy)null, options)
 219        {
 220        }
 221
 222        /// <summary>
 223        /// Initializes a new instance of the <see cref="QueueClient"/>
 224        /// class.
 225        /// </summary>
 226        /// <param name="queueUri">
 227        /// A <see cref="Uri"/> referencing the queue that includes the
 228        /// name of the account, and the name of the queue.
 229        /// This is likely to be similar to "https://{account_name}.queue.core.windows.net/{queue_name}".
 230        /// </param>
 231        /// <param name="credential">
 232        /// The shared key credential used to sign requests.
 233        /// </param>
 234        /// <param name="options">
 235        /// Optional client options that define the transport pipeline
 236        /// policies for authentication, retries, etc., that are applied to
 237        /// every request.
 238        /// </param>
 239        public QueueClient(Uri queueUri, StorageSharedKeyCredential credential, QueueClientOptions options = default)
 240            : this(queueUri, credential.AsPolicy(), options)
 241        {
 242        }
 243
 244        /// <summary>
 245        /// Initializes a new instance of the <see cref="QueueClient"/>
 246        /// class.
 247        /// </summary>
 248        /// <param name="queueUri">
 249        /// A <see cref="Uri"/> referencing the queue that includes the
 250        /// name of the account, and the name of the queue.
 251        /// This is likely to be similar to "https://{account_name}.queue.core.windows.net/{queue_name}".
 252        /// </param>
 253        /// <param name="credential">
 254        /// The token credential used to sign requests.
 255        /// </param>
 256        /// <param name="options">
 257        /// Optional client options that define the transport pipeline
 258        /// policies for authentication, retries, etc., that are applied to
 259        /// every request.
 260        /// </param>
 261        public QueueClient(Uri queueUri, TokenCredential credential, QueueClientOptions options = default)
 262            : this(queueUri, credential.AsPolicy(), options)
 263        {
 264            Errors.VerifyHttpsTokenAuth(queueUri);
 265        }
 266
 267        /// <summary>
 268        /// Initializes a new instance of the <see cref="QueueClient"/>
 269        /// class.
 270        /// </summary>
 271        /// <param name="queueUri">
 272        /// A <see cref="Uri"/> referencing the queue that includes the
 273        /// name of the account, and the name of the queue.
 274        /// This is likely to be similar to "https://{account_name}.queue.core.windows.net/{queue_name}".
 275        /// </param>
 276        /// <param name="authentication">
 277        /// An optional authentication policy used to sign requests.
 278        /// </param>
 279        /// <param name="options">
 280        /// Optional client options that define the transport pipeline
 281        /// policies for authentication, retries, etc., that are applied to
 282        /// every request.
 283        /// </param>
 284        internal QueueClient(Uri queueUri, HttpPipelinePolicy authentication, QueueClientOptions options)
 285        {
 286            _uri = queueUri;
 287            _messagesUri = queueUri.AppendToPath(Constants.Queue.MessagesUri);
 288            options ??= new QueueClientOptions();
 289            _pipeline = options.Build(authentication);
 290            _version = options.Version;
 291            _clientDiagnostics = new ClientDiagnostics(options);
 292            _clientSideEncryption = QueueClientSideEncryptionOptions.CloneFrom(options._clientSideEncryptionOptions);
 293        }
 294
 295        /// <summary>
 296        /// Initializes a new instance of the <see cref="QueueClient"/>
 297        /// class.
 298        /// </summary>
 299        /// <param name="queueUri">
 300        /// A <see cref="Uri"/> referencing the queue that includes the
 301        /// name of the account, and the name of the queue.
 302        /// This is likely to be similar to "https://{account_name}.queue.core.windows.net/{queue_name}".
 303        /// </param>
 304        /// <param name="pipeline">
 305        /// The transport pipeline used to send every request.
 306        /// </param>
 307        /// <param name="version">
 308        /// The version of the service to use when sending requests.
 309        /// </param>
 310        /// <param name="clientDiagnostics">
 311        /// The <see cref="ClientDiagnostics"/> instance used to create
 312        /// diagnostic scopes every request.
 313        /// </param>
 314        /// <param name="encryptionOptions">
 315        /// Options for client-side encryption.
 316        /// </param>
 317        internal QueueClient(
 318            Uri queueUri,
 319            HttpPipeline pipeline,
 320            QueueClientOptions.ServiceVersion version,
 321            ClientDiagnostics clientDiagnostics,
 322            ClientSideEncryptionOptions encryptionOptions)
 323        {
 324            _uri = queueUri;
 325            _messagesUri = queueUri.AppendToPath(Constants.Queue.MessagesUri);
 326            _pipeline = pipeline;
 327            _version = version;
 328            _clientDiagnostics = clientDiagnostics;
 329            _clientSideEncryption = QueueClientSideEncryptionOptions.CloneFrom(encryptionOptions);
 330        }
 331        #endregion ctors
 332
 333        /// <summary>
 334        /// Sets the various name fields if they are currently null.
 335        /// </summary>
 336        private void SetNameFieldsIfNull()
 337        {
 338            if (_name == null || _accountName == null)
 339            {
 340                var builder = new QueueUriBuilder(Uri);
 341                _name = builder.QueueName;
 342                _accountName = builder.AccountName;
 343            }
 344        }
 345
 346        #region Create
 347        /// <summary>
 348        /// Creates a queue.
 349        ///
 350        /// For more information, see
 351        /// <see href="https://docs.microsoft.com/rest/api/storageservices/create-queue4">
 352        /// Create Queue</see>.
 353        /// </summary>
 354        /// <param name="metadata">
 355        /// Optional <see cref="Metadata"/>.
 356        /// </param>
 357        /// <param name="cancellationToken">
 358        /// <see cref="CancellationToken"/>
 359        /// </param>
 360        /// <returns>
 361        /// <see cref="Response" />
 362        /// </returns>
 363        public virtual Response Create(
 364            Metadata metadata = default,
 365            CancellationToken cancellationToken = default) =>
 366            CreateInternal(
 367                metadata,
 368                false, // async
 369                cancellationToken)
 370                .EnsureCompleted();
 371
 372        /// <summary>
 373        /// Creates a queue.
 374        ///
 375        /// For more information, see
 376        /// <see href="https://docs.microsoft.com/rest/api/storageservices/create-queue4">
 377        /// Create Queue</see>.
 378        /// </summary>
 379        /// <param name="metadata">
 380        /// Optional <see cref="Metadata"/>.
 381        /// </param>
 382        /// <param name="cancellationToken">
 383        /// <see cref="CancellationToken"/>
 384        /// </param>
 385        /// <returns>
 386        /// <see cref="Response"/>
 387        /// </returns>
 388        public virtual async Task<Response> CreateAsync(
 389            Metadata metadata = default,
 390            CancellationToken cancellationToken = default) =>
 391            await CreateInternal(
 392                metadata,
 393                true, // async
 394                cancellationToken)
 395                .ConfigureAwait(false);
 396
 397        /// <summary>
 398        /// Creates a queue.
 399        ///
 400        /// For more information, see
 401        /// <see href="https://docs.microsoft.com/rest/api/storageservices/create-queue4">
 402        /// Create Queue</see>.
 403        /// </summary>
 404        /// <param name="metadata">
 405        /// Optional <see cref="Metadata"/>.
 406        /// </param>
 407        /// <param name="async">
 408        /// Whether to invoke the operation asynchronously.
 409        /// </param>
 410        /// <param name="cancellationToken">
 411        /// <see cref="CancellationToken"/>
 412        /// </param>
 413        /// <param name="operationName">
 414        /// Optional. To indicate if the name of the operation.
 415        /// </param>
 416        /// <returns>
 417        /// <see cref="Response"/>
 418        /// </returns>
 419        private async Task<Response> CreateInternal(
 420            Metadata metadata,
 421            bool async,
 422            CancellationToken cancellationToken,
 423            string operationName = default)
 424        {
 425            using (Pipeline.BeginLoggingScope(nameof(QueueClient)))
 426            {
 427                Pipeline.LogMethodEnter(
 428                    nameof(QueueClient),
 429                    message: $"{nameof(Uri)}: {Uri}");
 430                try
 431                {
 432                    return await QueueRestClient.Queue.CreateAsync(
 433                        ClientDiagnostics,
 434                        Pipeline,
 435                        Uri,
 436                        version: Version.ToVersionString(),
 437                        metadata: metadata,
 438                        async: async,
 439                        operationName: operationName ?? $"{nameof(QueueClient)}.{nameof(Create)}",
 440                        cancellationToken: cancellationToken)
 441                        .ConfigureAwait(false);
 442                }
 443                catch (Exception ex)
 444                {
 445                    Pipeline.LogException(ex);
 446                    throw;
 447                }
 448                finally
 449                {
 450                    Pipeline.LogMethodExit(nameof(QueueClient));
 451                }
 452            }
 453        }
 454        #endregion Create
 455
 456        #region CreateIfNotExists
 457        /// <summary>
 458        /// The <see cref="CreateIfNotExists"/>
 459        /// operation creates a new queue under the specified account.
 460        /// If the queue already exists, it is not changed.
 461        ///
 462        /// For more information, see
 463        /// <see href="https://docs.microsoft.com/rest/api/storageservices/create-queue4">
 464        /// Create Queue</see>.
 465        /// </summary>
 466        /// <param name="metadata">
 467        /// Optional custom metadata to set for this queue.
 468        /// </param>
 469        /// <param name="cancellationToken">
 470        /// Optional <see cref="CancellationToken"/> to propagate
 471        /// notifications that the operation should be cancelled.
 472        /// </param>
 473        /// <returns>
 474        /// If the queue does not already exist, a <see cref="Response"/>
 475        /// describing the newly created queue. If the queue already exists, <c>null</c>.
 476        /// </returns>
 477        /// <remarks>
 478        /// A <see cref="RequestFailedException"/> will be thrown if
 479        /// a failure occurs.
 480        /// </remarks>
 481        public virtual Response CreateIfNotExists(
 482            Metadata metadata = default,
 483            CancellationToken cancellationToken = default) =>
 484            CreateIfNotExistsInternal(
 485                metadata,
 486                async: false,
 487                cancellationToken).EnsureCompleted();
 488
 489        /// <summary>
 490        /// The <see cref="CreateIfNotExistsAsync"/>
 491        /// operation creates a new queue under the specified account.
 492        /// If the queue already exists, it is not changed.
 493        ///
 494        /// For more information, see
 495        /// <see href="https://docs.microsoft.com/rest/api/storageservices/create-queue4">
 496        /// Create Queue</see>.
 497        /// </summary>
 498        /// <param name="metadata">
 499        /// Optional custom metadata to set for this queue.
 500        /// </param>
 501        /// <param name="cancellationToken">
 502        /// Optional <see cref="CancellationToken"/> to propagate
 503        /// notifications that the operation should be cancelled.
 504        /// </param>
 505        /// <returns>
 506        /// If the queue does not already exist, a <see cref="Response"/>
 507        /// describing the newly created queue. If the queue already exists, <c>null</c>.
 508        /// </returns>
 509        /// <remarks>
 510        /// A <see cref="RequestFailedException"/> will be thrown if
 511        /// a failure occurs.
 512        /// </remarks>
 513        public virtual async Task<Response> CreateIfNotExistsAsync(
 514            Metadata metadata = default,
 515            CancellationToken cancellationToken = default) =>
 516            await CreateIfNotExistsInternal(
 517                metadata,
 518                async: true,
 519                cancellationToken).ConfigureAwait(false);
 520
 521        /// <summary>
 522        /// The <see cref="CreateIfNotExistsInternal"/>
 523        /// operation creates a new queue under the specified account.
 524        /// If the queue already exists, it is not changed.
 525        ///
 526        /// For more information, see
 527        /// <see href="https://docs.microsoft.com/rest/api/storageservices/create-queue4">
 528        /// Create Queue</see>.
 529        /// </summary>
 530        /// <param name="metadata">
 531        /// Optional custom metadata to set for this queue.
 532        /// </param>
 533        /// <param name="async">
 534        /// Whether to invoke the operation asynchronously.
 535        /// </param>
 536        /// <param name="cancellationToken">
 537        /// Optional <see cref="CancellationToken"/> to propagate
 538        /// notifications that the operation should be cancelled.
 539        /// </param>
 540        /// <returns>
 541        /// If the queue does not already exist, a <see cref="Response"/>
 542        /// describing the newly created queue. If the queue already exists, <c>null</c>.
 543        /// </returns>
 544        /// <remarks>
 545        /// A <see cref="RequestFailedException"/> will be thrown if
 546        /// a failure occurs.
 547        /// </remarks>
 548        private async Task<Response> CreateIfNotExistsInternal(
 549            Metadata metadata,
 550            bool async,
 551            CancellationToken cancellationToken)
 552        {
 553            using (Pipeline.BeginLoggingScope(nameof(QueueClient)))
 554            {
 555                Pipeline.LogMethodEnter(
 556                    nameof(QueueClient),
 557                    message:
 558                    $"{nameof(Uri)}: {Uri}\n" +
 559                    $"{nameof(metadata)}: {metadata}");
 560                Response response;
 561                try
 562                {
 563                    response = await CreateInternal(
 564                        metadata,
 565                        async,
 566                        cancellationToken,
 567                        $"{nameof(QueueClient)}.{nameof(CreateIfNotExists)}")
 568                        .ConfigureAwait(false);
 569
 570                    if (response.Status == Constants.Queue.StatusCodeNoContent)
 571                    {
 572                        response = default;
 573                    }
 574                }
 575                catch (RequestFailedException storageRequestFailedException)
 576                when (storageRequestFailedException.ErrorCode == QueueErrorCode.QueueAlreadyExists)
 577                {
 578                    response = default;
 579                }
 580                catch (Exception ex)
 581                {
 582                    Pipeline.LogException(ex);
 583                    throw;
 584                }
 585                finally
 586                {
 587                    Pipeline.LogMethodExit(nameof(QueueClient));
 588                }
 589                return response;
 590            }
 591        }
 592        #endregion CreateIfNotExists
 593
 594        #region Exists
 595        /// <summary>
 596        /// The <see cref="Exists"/> operation can be called on a
 597        /// <see cref="QueueClient"/> to see if the associated queue
 598        /// exists on the storage account in the storage service.
 599        /// </summary>
 600        /// <param name="cancellationToken">
 601        /// Optional <see cref="CancellationToken"/> to propagate
 602        /// notifications that the operation should be cancelled.
 603        /// </param>
 604        /// <returns>
 605        /// Returns true if the queue exists.
 606        /// </returns>
 607        /// <remarks>
 608        /// A <see cref="RequestFailedException"/> will be thrown if
 609        /// a failure occurs.
 610        /// </remarks>
 611        public virtual Response<bool> Exists(
 612            CancellationToken cancellationToken = default) =>
 613            ExistsInternal(
 614                async: false,
 615                cancellationToken).EnsureCompleted();
 616
 617        /// <summary>
 618        /// The <see cref="ExistsAsync"/> operation can be called on a
 619        /// <see cref="QueueClient"/> to see if the associated queue
 620        /// exists on the storage account in the storage service.
 621        /// </summary>
 622        /// <param name="cancellationToken">
 623        /// Optional <see cref="CancellationToken"/> to propagate
 624        /// notifications that the operation should be cancelled.
 625        /// </param>
 626        /// <returns>
 627        /// Returns true if the queue exists.
 628        /// </returns>
 629        /// <remarks>
 630        /// A <see cref="RequestFailedException"/> will be thrown if
 631        /// a failure occurs.
 632        /// </remarks>
 633        public virtual async Task<Response<bool>> ExistsAsync(
 634            CancellationToken cancellationToken = default) =>
 635            await ExistsInternal(
 636                async: true,
 637                cancellationToken).ConfigureAwait(false);
 638
 639        /// <summary>
 640        /// The <see cref="ExistsInternal"/> operation can be called on a
 641        /// <see cref="QueueClient"/> to see if the associated queue
 642        /// exists on the storage account in the storage service.
 643        /// </summary>
 644        /// <param name="async">
 645        /// Whether to invoke the operation asynchronously.
 646        /// </param>
 647        /// <param name="cancellationToken">
 648        /// Optional <see cref="CancellationToken"/> to propagate
 649        /// notifications that the operation should be cancelled.
 650        /// </param>
 651        /// <returns>
 652        /// Returns true if the queue exists.
 653        /// </returns>
 654        /// <remarks>
 655        /// A <see cref="RequestFailedException"/> will be thrown if
 656        /// a failure occurs.
 657        /// </remarks>
 658        private async Task<Response<bool>> ExistsInternal(
 659            bool async,
 660            CancellationToken cancellationToken)
 661        {
 662            using (Pipeline.BeginLoggingScope(nameof(QueueClient)))
 663            {
 664                Pipeline.LogMethodEnter(
 665                    nameof(QueueClient),
 666                    message:
 667                    $"{nameof(Uri)}: {Uri}");
 668
 669                try
 670                {
 671                    Response<QueueProperties> response = await GetPropertiesInternal(
 672                        async: async,
 673                        operationName: $"{nameof(QueueClient)}.{nameof(Exists)}",
 674                        cancellationToken: cancellationToken)
 675                        .ConfigureAwait(false);
 676
 677                    return Response.FromValue(true, response.GetRawResponse());
 678                }
 679                catch (RequestFailedException storageRequestFailedException)
 680                when (storageRequestFailedException.ErrorCode == QueueErrorCode.QueueNotFound)
 681                {
 682                    return Response.FromValue(false, default);
 683                }
 684                catch (Exception ex)
 685                {
 686                    Pipeline.LogException(ex);
 687                    throw;
 688                }
 689                finally
 690                {
 691                    Pipeline.LogMethodExit(nameof(QueueClient));
 692                }
 693            }
 694        }
 695        #endregion Exists
 696
 697        #region DeleteIfExists
 698        /// <summary>
 699        /// The <see cref="DeleteIfExists"/> operation deletes the specified
 700        /// queue if it exists.
 701        ///
 702        /// For more information, see
 703        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/delete-queue3">
 704        /// Delete Queue</see>.
 705        /// </summary>
 706        /// <param name="cancellationToken">
 707        /// Optional <see cref="CancellationToken"/> to propagate
 708        /// notifications that the operation should be cancelled.
 709        /// </param>
 710        /// <returns>
 711        /// A <see cref="Response"/> Returns true if queue exists and was
 712        /// deleted, return false otherwise.
 713        /// </returns>
 714        /// <remarks>
 715        /// A <see cref="RequestFailedException"/> will be thrown if
 716        /// a failure occurs.
 717        /// </remarks>
 718        public virtual Response<bool> DeleteIfExists(
 719            CancellationToken cancellationToken = default) =>
 720            DeleteIfExistsInternal(
 721                async: false,
 722                cancellationToken).EnsureCompleted();
 723
 724        /// <summary>
 725        /// The <see cref="DeleteIfExistsAsync"/> operation deletes the specified
 726        /// queue if it exists.
 727        ///
 728        /// For more information, see
 729        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/delete-queue3">
 730        /// Delete Queue</see>.
 731        /// </summary>
 732        /// <param name="cancellationToken">
 733        /// Optional <see cref="CancellationToken"/> to propagate
 734        /// notifications that the operation should be cancelled.
 735        /// </param>
 736        /// <returns>
 737        /// A <see cref="Response"/> Returns true if queue exists and was
 738        /// deleted, return false otherwise.
 739        /// </returns>
 740        /// <remarks>
 741        /// A <see cref="RequestFailedException"/> will be thrown if
 742        /// a failure occurs.
 743        /// </remarks>
 744        public virtual async Task<Response<bool>> DeleteIfExistsAsync(
 745            CancellationToken cancellationToken = default) =>
 746            await DeleteIfExistsInternal(
 747                async: true,
 748                cancellationToken).ConfigureAwait(false);
 749
 750        /// <summary>
 751        /// The <see cref="DeleteIfExistsInternal"/> operation deletes the specified
 752        /// queue if it exists.
 753        ///
 754        /// For more information, see
 755        /// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/delete-queue3">
 756        /// Delete Queue</see>.
 757        /// </summary>
 758        /// <param name="async">
 759        /// Whether to invoke the operation asynchronously.
 760        /// </param>
 761        /// <param name="cancellationToken">
 762        /// Optional <see cref="CancellationToken"/> to propagate
 763        /// notifications that the operation should be cancelled.
 764        /// </param>
 765        /// <returns>
 766        /// A <see cref="Response"/> Returns true if queue exists and was
 767        /// deleted, return false otherwise.
 768        /// </returns>
 769        /// <remarks>
 770        /// A <see cref="RequestFailedException"/> will be thrown if
 771        /// a failure occurs.
 772        /// </remarks>
 773        private async Task<Response<bool>> DeleteIfExistsInternal(
 774            bool async,
 775            CancellationToken cancellationToken)
 776        {
 777            using (Pipeline.BeginLoggingScope(nameof(QueueClient)))
 778            {
 779                Pipeline.LogMethodEnter(
 780                    nameof(QueueClient),
 781                    message:
 782                    $"{nameof(Uri)}: {Uri}");
 783                try
 784                {
 785                    Response response = await DeleteInternal(
 786                        async,
 787                        cancellationToken,
 788                        $"{nameof(QueueClient)}.{nameof(DeleteIfExists)}")
 789                        .ConfigureAwait(false);
 790                    return Response.FromValue(true, response);
 791                }
 792                catch (RequestFailedException storageRequestFailedException)
 793                when (storageRequestFailedException.ErrorCode == QueueErrorCode.QueueNotFound)
 794                {
 795                    return Response.FromValue(false, default);
 796                }
 797                catch (Exception ex)
 798                {
 799                    Pipeline.LogException(ex);
 800                    throw;
 801                }
 802                finally
 803                {
 804                    Pipeline.LogMethodExit(nameof(QueueClient));
 805                }
 806            }
 807        }
 808        #endregion DeleteIfExists
 809
 810        #region Delete
 811        /// <summary>
 812        /// Deletes a queue.
 813        ///
 814        /// For more information, see
 815        /// <see href="https://docs.microsoft.com/rest/api/storageservices/delete-queue3">
 816        /// Delete Queue</see>.
 817        /// </summary>
 818        /// <param name="cancellationToken">
 819        /// <see cref="CancellationToken"/>
 820        /// </param>
 821        /// <returns>
 822        /// <see cref="Response"/>
 823        /// </returns>
 824        public virtual Response Delete(
 825            CancellationToken cancellationToken = default) =>
 826            DeleteInternal(
 827                false, // async
 828                cancellationToken)
 829                .EnsureCompleted();
 830
 831        /// <summary>
 832        /// Deletes a queue.
 833        ///
 834        /// For more information, see
 835        /// <see href="https://docs.microsoft.com/rest/api/storageservices/delete-queue3">
 836        /// Delete Queue</see>.
 837        /// </summary>
 838        /// <param name="cancellationToken">
 839        /// <see cref="CancellationToken"/>
 840        /// </param>
 841        /// <returns>
 842        /// <see cref="Response"/>
 843        /// </returns>
 844        public virtual async Task<Response> DeleteAsync(
 845            CancellationToken cancellationToken = default) =>
 846            await DeleteInternal(
 847                true, // async
 848                cancellationToken)
 849                .ConfigureAwait(false);
 850
 851        /// <summary>
 852        /// Deletes a queue.
 853        ///
 854        /// For more information, see
 855        /// <see href="https://docs.microsoft.com/rest/api/storageservices/delete-queue3">
 856        /// Delete Queue</see>.
 857        /// </summary>
 858        /// <param name="async">
 859        /// Whether to invoke the operation asynchronously.
 860        /// </param>
 861        /// <param name="cancellationToken">
 862        /// <see cref="CancellationToken"/>
 863        /// </param>
 864        /// <param name="operationName">
 865        /// Optional. To indicate if the name of the operation.
 866        /// </param>
 867        /// <returns>
 868        /// <see cref="Response"/>
 869        /// </returns>
 870        private async Task<Response> DeleteInternal(
 871            bool async,
 872            CancellationToken cancellationToken,
 873            string operationName = default)
 874        {
 875            using (Pipeline.BeginLoggingScope(nameof(QueueClient)))
 876            {
 877                Pipeline.LogMethodEnter(
 878                    nameof(QueueClient),
 879                    message: $"{nameof(Uri)}: {Uri}");
 880                try
 881                {
 882                    return await QueueRestClient.Queue.DeleteAsync(
 883                        ClientDiagnostics,
 884                        Pipeline,
 885                        Uri,
 886                        version: Version.ToVersionString(),
 887                        async: async,
 888                        operationName: operationName ?? $"{nameof(QueueClient)}.{nameof(Delete)}",
 889                        cancellationToken: cancellationToken)
 890                        .ConfigureAwait(false);
 891                }
 892                catch (Exception ex)
 893                {
 894                    Pipeline.LogException(ex);
 895                    throw;
 896                }
 897                finally
 898                {
 899                    Pipeline.LogMethodExit(nameof(QueueClient));
 900                }
 901            }
 902        }
 903        #endregion Delete
 904
 905        #region GetProperties
 906        /// <summary>
 907        /// Retrieves queue properties and user-defined metadata and properties on the specified queue.
 908        /// Metadata is associated with the queue as name-values pairs.
 909        ///
 910        /// For more information, see
 911        /// <see href="https://docs.microsoft.com/rest/api/storageservices/get-queue-metadata">
 912        /// Get Queue Metadata</see>.
 913        /// </summary>
 914        /// <param name="cancellationToken">
 915        /// <see cref="CancellationToken"/>
 916        /// </param>
 917        /// <returns>
 918        /// <see cref="Response{QueueProperties}"/>
 919        /// </returns>
 920        public virtual Response<QueueProperties> GetProperties(
 921            CancellationToken cancellationToken = default) =>
 922            GetPropertiesInternal(
 923                false, // async
 924                cancellationToken)
 925                .EnsureCompleted();
 926
 927        /// <summary>
 928        /// Retrieves queue properties and user-defined metadata and properties on the specified queue.
 929        /// Metadata is associated with the queue as name-values pairs.
 930        ///
 931        /// For more information, see
 932        /// <see href="https://docs.microsoft.com/rest/api/storageservices/get-queue-metadata">
 933        /// Get Queue Metadata</see>.
 934        /// </summary>
 935        /// <param name="cancellationToken">
 936        /// <see cref="CancellationToken"/>
 937        /// </param>
 938        /// <returns>
 939        /// <see cref="Response{QueueProperties}"/>
 940        /// </returns>
 941        public virtual async Task<Response<QueueProperties>> GetPropertiesAsync(
 942            CancellationToken cancellationToken = default) =>
 943            await GetPropertiesInternal(
 944                true, // async
 945                cancellationToken)
 946                .ConfigureAwait(false);
 947
 948        /// <summary>
 949        /// Retrieves queue properties and user-defined metadata and properties on the specified queue.
 950        /// Metadata is associated with the queue as name-values pairs.
 951        ///
 952        /// For more information, see
 953        /// <see href="https://docs.microsoft.com/rest/api/storageservices/get-queue-metadata">
 954        /// Get Queue Metadata</see>.
 955        /// </summary>
 956        /// <param name="async">
 957        /// Whether to invoke the operation asynchronously.
 958        /// </param>
 959        /// <param name="cancellationToken">
 960        /// <see cref="CancellationToken"/>
 961        /// </param>
 962        /// <param name="operationName">
 963        /// Optional. To indicate if the name of the operation.
 964        /// </param>
 965        /// <returns>
 966        /// <see cref="Response{QueueProperties}"/>
 967        /// </returns>
 968        private async Task<Response<QueueProperties>> GetPropertiesInternal(
 969            bool async,
 970            CancellationToken cancellationToken,
 971            string operationName = default)
 972        {
 973            using (Pipeline.BeginLoggingScope(nameof(QueueClient)))
 974            {
 975                Pipeline.LogMethodEnter(
 976                    nameof(QueueClient),
 977                    message: $"{nameof(Uri)}: {Uri}");
 978                try
 979                {
 980                    return await QueueRestClient.Queue.GetPropertiesAsync(
 981                        ClientDiagnostics,
 982                        Pipeline,
 983                        Uri,
 984                        version: Version.ToVersionString(),
 985                        async: async,
 986                        operationName: operationName ?? $"{nameof(QueueClient)}.{nameof(GetProperties)}",
 987                        cancellationToken: cancellationToken)
 988                        .ConfigureAwait(false);
 989                }
 990                catch (Exception ex)
 991                {
 992                    Pipeline.LogException(ex);
 993                    throw;
 994                }
 995                finally
 996                {
 997                    Pipeline.LogMethodExit(nameof(QueueClient));
 998                }
 999            }
 1000        }
 1001        #endregion GetProperties
 1002
 1003        #region SetMetadata
 1004        /// <summary>
 1005        /// Sets user-defined metadata on the specified queue. Metadata is associated with the queue as name-value pairs
 1006        ///
 1007        /// For more information, see
 1008        /// <see href="https://docs.microsoft.com/rest/api/storageservices/set-queue-metadata">
 1009        /// Set Queue Metadata</see>.
 1010        /// </summary>
 1011        /// <param name="metadata">
 1012        /// <see cref="Metadata"/>
 1013        /// </param>
 1014        /// <param name="cancellationToken">
 1015        /// <see cref="CancellationToken"/>
 1016        /// </param>
 1017        /// <returns>
 1018        /// <see cref="Response"/>
 1019        /// </returns>
 1020        public virtual Response SetMetadata(
 1021            Metadata metadata,
 1022            CancellationToken cancellationToken = default) =>
 1023            SetMetadataInternal(
 1024                metadata,
 1025                false, // async
 1026                cancellationToken)
 1027                .EnsureCompleted();
 1028
 1029        /// <summary>
 1030        /// Sets user-defined metadata on the specified queue. Metadata is associated with the queue as name-value pairs
 1031        ///
 1032        /// For more information, see
 1033        /// <see href="https://docs.microsoft.com/rest/api/storageservices/set-queue-metadata">
 1034        /// Set Queue Metadata</see>.
 1035        /// </summary>
 1036        /// <param name="metadata">
 1037        /// <see cref="Metadata"/>
 1038        /// </param>
 1039        /// <param name="cancellationToken">
 1040        /// <see cref="CancellationToken"/>
 1041        /// </param>
 1042        /// <returns>
 1043        /// <see cref="Response"/>
 1044        /// </returns>
 1045        public virtual async Task<Response> SetMetadataAsync(
 1046            Metadata metadata,
 1047            CancellationToken cancellationToken = default) =>
 1048            await SetMetadataInternal(
 1049                metadata,
 1050                true, // async
 1051                cancellationToken)
 1052                .ConfigureAwait(false);
 1053
 1054        /// <summary>
 1055        /// Sets user-defined metadata on the specified queue. Metadata is associated with the queue as name-value pairs
 1056        ///
 1057        /// For more information, see
 1058        /// <see href="https://docs.microsoft.com/rest/api/storageservices/set-queue-metadata">
 1059        /// Set Queue Metadata</see>.
 1060        /// </summary>
 1061        /// <param name="metadata">
 1062        /// <see cref="Metadata"/>
 1063        /// </param>
 1064        /// <param name="async">
 1065        /// Whether to invoke the operation asynchronously.
 1066        /// </param>
 1067        /// <param name="cancellationToken">
 1068        /// <see cref="CancellationToken"/>
 1069        /// </param>
 1070        /// <returns>
 1071        /// <see cref="Response"/>
 1072        /// </returns>
 1073        private async Task<Response> SetMetadataInternal(
 1074            Metadata metadata,
 1075            bool async,
 1076            CancellationToken cancellationToken)
 1077        {
 1078            using (Pipeline.BeginLoggingScope(nameof(QueueClient)))
 1079            {
 1080                Pipeline.LogMethodEnter(
 1081                    nameof(QueueClient),
 1082                    message: $"{nameof(Uri)}: {Uri}");
 1083                try
 1084                {
 1085                    return await QueueRestClient.Queue.SetMetadataAsync(
 1086                        ClientDiagnostics,
 1087                        Pipeline,
 1088                        Uri,
 1089                        version: Version.ToVersionString(),
 1090                        metadata: metadata,
 1091                        async: async,
 1092                        cancellationToken: cancellationToken)
 1093                        .ConfigureAwait(false);
 1094                }
 1095                catch (Exception ex)
 1096                {
 1097                    Pipeline.LogException(ex);
 1098                    throw;
 1099                }
 1100                finally
 1101                {
 1102                    Pipeline.LogMethodExit(nameof(QueueClient));
 1103                }
 1104            }
 1105        }
 1106        #endregion SetMetadata
 1107
 1108        #region GetAccessPolicy
 1109        /// <summary>
 1110        /// Returns details about any stored access policies specified on the queue that may be used with
 1111        /// Shared Access Signatures.
 1112        ///
 1113        /// For more information, see
 1114        /// <see href="https://docs.microsoft.com/rest/api/storageservices/get-queue-acl">
 1115        /// Get Queue ACL</see>.
 1116        /// </summary>
 1117        /// <param name="cancellationToken">
 1118        /// <see cref="CancellationToken"/>
 1119        /// </param>
 1120        /// <returns>
 1121        /// <see cref="Response{T}"/> of <see cref="IEnumerable{SignedIdentifier}" />
 1122        /// </returns>
 1123        public virtual Response<IEnumerable<QueueSignedIdentifier>> GetAccessPolicy(
 1124            CancellationToken cancellationToken = default) =>
 1125            GetAccessPolicyInternal(
 1126                false, // async
 1127                cancellationToken)
 1128                .EnsureCompleted();
 1129
 1130        /// <summary>
 1131        /// Returns details about any stored access policies specified on the queue that may be used with
 1132        /// Shared Access Signatures.
 1133        ///
 1134        /// For more information, see
 1135        /// <see href="https://docs.microsoft.com/rest/api/storageservices/get-queue-acl">
 1136        /// Get Queue ACL</see>.
 1137        /// </summary>
 1138        /// <param name="cancellationToken">
 1139        /// <see cref="CancellationToken"/>
 1140        /// </param>
 1141        /// <returns>
 1142        /// <see cref="Response{T}"/> of <see cref="IEnumerable{SignedIdentifier}" />
 1143        /// </returns>
 1144        public virtual async Task<Response<IEnumerable<QueueSignedIdentifier>>> GetAccessPolicyAsync(
 1145            CancellationToken cancellationToken = default) =>
 1146            await GetAccessPolicyInternal(
 1147                true, // async
 1148                cancellationToken)
 1149                .ConfigureAwait(false);
 1150
 1151        /// <summary>
 1152        /// Returns details about any stored access policies specified on the queue that may be used with
 1153        /// Shared Access Signatures.
 1154        ///
 1155        /// For more information, see
 1156        /// <see href="https://docs.microsoft.com/rest/api/storageservices/get-queue-acl">
 1157        /// Get Queue ACL</see>.
 1158        /// </summary>
 1159        /// <param name="async">
 1160        /// Whether to invoke the operation asynchronously.
 1161        /// </param>
 1162        /// <param name="cancellationToken">
 1163        /// <see cref="CancellationToken"/>
 1164        /// </param>
 1165        /// <returns>
 1166        /// <see cref="Response{T}"/> of <see cref="IEnumerable{SignedIdentifier}" />
 1167        /// </returns>
 1168        private async Task<Response<IEnumerable<QueueSignedIdentifier>>> GetAccessPolicyInternal(
 1169            bool async,
 1170            CancellationToken cancellationToken)
 1171        {
 1172            using (Pipeline.BeginLoggingScope(nameof(QueueClient)))
 1173            {
 1174                Pipeline.LogMethodEnter(
 1175                    nameof(QueueClient),
 1176                    message: $"{nameof(Uri)}: {Uri}");
 1177                try
 1178                {
 1179                    return await QueueRestClient.Queue.GetAccessPolicyAsync(
 1180                        ClientDiagnostics,
 1181                        Pipeline,
 1182                        Uri,
 1183                        version: Version.ToVersionString(),
 1184                        async: async,
 1185                        cancellationToken: cancellationToken)
 1186                        .ConfigureAwait(false);
 1187                }
 1188                catch (Exception ex)
 1189                {
 1190                    Pipeline.LogException(ex);
 1191                    throw;
 1192                }
 1193                finally
 1194                {
 1195                    Pipeline.LogMethodExit(nameof(QueueClient));
 1196                }
 1197            }
 1198        }
 1199        #endregion GetAccessPolicy
 1200
 1201        #region SetAccessPolicy
 1202        /// <summary>
 1203        /// SetAccessPolicyAsync sets stored access policies for the queue that may be used with Shared Access Signature
 1204        ///
 1205        /// For more information, see
 1206        /// <see href="https://docs.microsoft.com/rest/api/storageservices/set-queue-acl">
 1207        /// Set Queue ACL</see>.
 1208        /// </summary>
 1209        /// <param name="permissions">
 1210        /// IEnumerable of <see cref="QueueSignedIdentifier"/>
 1211        /// </param>
 1212        /// <param name="cancellationToken">
 1213        /// <see cref="CancellationToken"/>
 1214        /// </param>
 1215        /// <returns>
 1216        /// <see cref="Response"/>
 1217        /// </returns>
 1218        public virtual Response SetAccessPolicy(
 1219            IEnumerable<QueueSignedIdentifier> permissions,
 1220            CancellationToken cancellationToken = default) =>
 1221            SetAccessPolicyInternal(
 1222                permissions,
 1223                false, // async
 1224                cancellationToken)
 1225                .EnsureCompleted();
 1226
 1227        /// <summary>
 1228        /// SetAccessPolicyAsync sets stored access policies for the queue that may be used with Shared Access Signature
 1229        ///
 1230        /// For more information, see
 1231        /// <see href="https://docs.microsoft.com/rest/api/storageservices/set-queue-acl">
 1232        /// Set Queue ACL</see>.
 1233        /// </summary>
 1234        /// <param name="permissions">
 1235        /// IEnumerable of <see cref="QueueSignedIdentifier"/>
 1236        /// </param>
 1237        /// <param name="cancellationToken">
 1238        /// <see cref="CancellationToken"/>
 1239        /// </param>
 1240        /// <returns>
 1241        /// <see cref="Response"/>
 1242        /// </returns>
 1243        public virtual async Task<Response> SetAccessPolicyAsync(
 1244            IEnumerable<QueueSignedIdentifier> permissions,
 1245            CancellationToken cancellationToken = default) =>
 1246            await SetAccessPolicyInternal(
 1247                permissions,
 1248                true, // async
 1249                cancellationToken)
 1250                .ConfigureAwait(false);
 1251
 1252        /// <summary>
 1253        /// SetAccessPolicyInternal sets stored access policies for the queue that may be used with Shared Access Signat
 1254        ///
 1255        /// For more information, see
 1256        /// <see href="https://docs.microsoft.com/rest/api/storageservices/set-queue-acl">
 1257        /// Set Queue ACL</see>.
 1258        /// </summary>
 1259        /// <param name="permissions">
 1260        /// IEnumerable of <see cref="QueueSignedIdentifier"/>
 1261        /// </param>
 1262        /// <param name="async">
 1263        /// Whether to invoke the operation asynchronously.
 1264        /// </param>
 1265        /// <param name="cancellationToken">
 1266        /// <see cref="CancellationToken"/>
 1267        /// </param>
 1268        /// <returns>
 1269        /// <see cref="Response"/>
 1270        /// </returns>
 1271        private async Task<Response> SetAccessPolicyInternal(
 1272            IEnumerable<QueueSignedIdentifier> permissions,
 1273            bool async,
 1274            CancellationToken cancellationToken)
 1275        {
 1276            using (Pipeline.BeginLoggingScope(nameof(QueueClient)))
 1277            {
 1278                Pipeline.LogMethodEnter(
 1279                    nameof(QueueClient),
 1280                    message: $"{nameof(Uri)}: {Uri}");
 1281                try
 1282                {
 1283                    return await QueueRestClient.Queue.SetAccessPolicyAsync(
 1284                        ClientDiagnostics,
 1285                        Pipeline,
 1286                        Uri,
 1287                        version: Version.ToVersionString(),
 1288                        permissions: permissions,
 1289                        async: async,
 1290                        cancellationToken: cancellationToken)
 1291                        .ConfigureAwait(false);
 1292                }
 1293                catch (Exception ex)
 1294                {
 1295                    Pipeline.LogException(ex);
 1296                    throw;
 1297                }
 1298                finally
 1299                {
 1300                    Pipeline.LogMethodExit(nameof(QueueClient));
 1301                }
 1302            }
 1303        }
 1304        #endregion SetAccessPolicy
 1305
 1306        #region ClearMessages
 1307        /// <summary>
 1308        /// Deletes all messages from a queue.
 1309        ///
 1310        /// For more information, see
 1311        /// <see href="https://docs.microsoft.com/rest/api/storageservices/clear-messages">
 1312        /// Clear Messages</see>.
 1313        /// </summary>
 1314        /// <param name="cancellationToken">
 1315        /// <see cref="CancellationToken"/>.
 1316        /// </param>
 1317        /// <returns>
 1318        /// <see cref="Response"/>
 1319        /// </returns>
 1320        public virtual Response ClearMessages(
 1321            CancellationToken cancellationToken = default) =>
 1322            ClearMessagesInternal(
 1323                false, // async
 1324                cancellationToken)
 1325                .EnsureCompleted();
 1326
 1327        /// <summary>
 1328        /// Deletes all messages from a queue.
 1329        ///
 1330        /// For more information, see
 1331        /// <see href="https://docs.microsoft.com/rest/api/storageservices/clear-messages">
 1332        /// Clear Messages</see>.
 1333        /// </summary>
 1334        /// <param name="cancellationToken">
 1335        /// <see cref="CancellationToken"/>.
 1336        /// </param>
 1337        /// <returns>
 1338        /// <see cref="Response"/>
 1339        /// </returns>
 1340        public virtual async Task<Response> ClearMessagesAsync(
 1341            CancellationToken cancellationToken = default) =>
 1342            await ClearMessagesInternal(
 1343                true, // async
 1344                cancellationToken)
 1345                .ConfigureAwait(false);
 1346
 1347        /// <summary>
 1348        /// Deletes all messages from a queue.
 1349        ///
 1350        /// For more information, see
 1351        /// <see href="https://docs.microsoft.com/rest/api/storageservices/clear-messages">
 1352        /// Clear Messages</see>.
 1353        /// </summary>
 1354        /// <param name="async">
 1355        /// Whether to invoke the operation asynchronously.
 1356        /// </param>
 1357        /// <param name="cancellationToken">
 1358        /// <see cref="CancellationToken"/>.
 1359        /// </param>
 1360        /// <returns>
 1361        /// <see cref="Response"/>
 1362        /// </returns>
 1363        private async Task<Response> ClearMessagesInternal(
 1364            bool async,
 1365            CancellationToken cancellationToken)
 1366        {
 1367            using (Pipeline.BeginLoggingScope(nameof(QueueClient)))
 1368            {
 1369                Pipeline.LogMethodEnter(
 1370                    nameof(QueueClient),
 1371                    message: $"Uri: {MessagesUri}");
 1372                try
 1373                {
 1374                    return await QueueRestClient.Messages.ClearAsync(
 1375                        ClientDiagnostics,
 1376                        Pipeline,
 1377                        MessagesUri,
 1378                        version: Version.ToVersionString(),
 1379                        async: async,
 1380                        operationName: $"{nameof(QueueClient)}.{nameof(ClearMessages)}",
 1381                        cancellationToken: cancellationToken)
 1382                        .ConfigureAwait(false);
 1383                }
 1384                catch (Exception ex)
 1385                {
 1386                    Pipeline.LogException(ex);
 1387                    throw;
 1388                }
 1389                finally
 1390                {
 1391                    Pipeline.LogMethodExit(nameof(QueueClient));
 1392                }
 1393            }
 1394        }
 1395        #endregion ClearMessages
 1396
 1397        #region SendMessage
 1398        /// <summary>
 1399        /// Adds a new message to the back of a queue. The visibility timeout specifies how long the message should be i
 1400        /// to Dequeue and Peek operations. The message content must be a UTF-8 encoded string that is up to 64KB in siz
 1401        ///
 1402        /// For more information, see
 1403        /// <see href="https://docs.microsoft.com/rest/api/storageservices/put-message">
 1404        /// Put Message</see>.
 1405        /// </summary>
 1406        /// <param name="messageText">
 1407        /// Message text.
 1408        /// </param>
 1409        /// <returns>
 1410        /// <see cref="Response{SendReceipt}"/>
 1411        /// </returns>
 1412        public virtual Response<SendReceipt> SendMessage(string messageText) =>
 1413            SendMessage(
 1414                messageText,
 1415                null); // Pass anything else so we don't recurse on this overload
 1416
 1417        /// <summary>
 1418        /// Adds a new message to the back of a queue. The visibility timeout specifies how long the message should be i
 1419        /// to Dequeue and Peek operations. The message content must be a UTF-8 encoded string that is up to 64KB in siz
 1420        ///
 1421        /// For more information, see
 1422        /// <see href="https://docs.microsoft.com/rest/api/storageservices/put-message">
 1423        /// Put Message</see>.
 1424        /// </summary>
 1425        /// <param name="messageText">
 1426        /// Message text.
 1427        /// </param>
 1428        /// <returns>
 1429        /// <see cref="Response{SendReceipt}"/>
 1430        /// </returns>
 1431        public virtual async Task<Response<SendReceipt>> SendMessageAsync(string messageText) =>
 1432            await SendMessageAsync(
 1433                messageText,
 1434                null) // Pass anything else so we don't recurse on this overload
 1435            .ConfigureAwait(false);
 1436
 1437        /// <summary>
 1438        /// Adds a new message to the back of a queue. The visibility timeout specifies how long the message should be i
 1439        /// to Dequeue and Peek operations. The message content must be a UTF-8 encoded string that is up to 64KB in siz
 1440        ///
 1441        /// For more information, see
 1442        /// <see href="https://docs.microsoft.com/rest/api/storageservices/put-message">
 1443        /// Put Message</see>.
 1444        /// </summary>
 1445        /// <param name="messageText">
 1446        /// Message text.
 1447        /// </param>
 1448        /// <param name="cancellationToken">
 1449        /// Optional <see cref="CancellationToken"/>.
 1450        /// </param>
 1451        /// <returns>
 1452        /// <see cref="Response{SendReceipt}"/>
 1453        /// </returns>
 1454        public virtual Response<SendReceipt> SendMessage(string messageText, CancellationToken cancellationToken = defau
 1455            SendMessage(
 1456                messageText,
 1457                cancellationToken: cancellationToken,
 1458                visibilityTimeout: default); // Pass anything else so we don't recurse on this overload
 1459
 1460        /// <summary>
 1461        /// Adds a new message to the back of a queue. The visibility timeout specifies how long the message should be i
 1462        /// to Dequeue and Peek operations. The message content must be a UTF-8 encoded string that is up to 64KB in siz
 1463        ///
 1464        /// For more information, see
 1465        /// <see href="https://docs.microsoft.com/rest/api/storageservices/put-message">
 1466        /// Put Message</see>.
 1467        /// </summary>
 1468        /// <param name="messageText">
 1469        /// Message text.
 1470        /// </param>
 1471        /// <param name="cancellationToken">
 1472        /// Optional <see cref="CancellationToken"/>.
 1473        /// </param>
 1474        /// <returns>
 1475        /// <see cref="Response{SendReceipt}"/>
 1476        /// </returns>
 1477        public virtual async Task<Response<SendReceipt>> SendMessageAsync(string messageText, CancellationToken cancella
 1478            await SendMessageAsync(messageText,
 1479                cancellationToken: cancellationToken,
 1480                visibilityTimeout: default) // Pass anything else so we don't recurse on this overload
 1481            .ConfigureAwait(false);
 1482
 1483        /// <summary>
 1484        /// Adds a new message to the back of a queue. The visibility timeout specifies how long the message should be i
 1485        /// to Dequeue and Peek operations. The message content must be a UTF-8 encoded string that is up to 64KB in siz
 1486        ///
 1487        /// For more information, see
 1488        /// <see href="https://docs.microsoft.com/rest/api/storageservices/put-message">
 1489        /// Put Message</see>.
 1490        /// </summary>
 1491        /// <param name="messageText">
 1492        /// Message text.
 1493        /// </param>
 1494        /// <param name="visibilityTimeout">
 1495        /// Visibility timeout.  Optional with a default value of 0.  Cannot be larger than 7 days.
 1496        /// </param>
 1497        /// <param name="timeToLive">
 1498        /// Optional. Specifies the time-to-live interval for the message
 1499        /// </param>
 1500        /// <param name="cancellationToken">
 1501        /// Optional <see cref="CancellationToken"/>.
 1502        /// </param>
 1503        /// <returns>
 1504        /// <see cref="Response{SendReceipt}"/>
 1505        /// </returns>
 1506        public virtual Response<SendReceipt> SendMessage(
 1507            string messageText,
 1508            TimeSpan? visibilityTimeout = default,
 1509            TimeSpan? timeToLive = default,
 1510            CancellationToken cancellationToken = default) =>
 1511            SendMessageInternal(
 1512                messageText,
 1513                visibilityTimeout,
 1514                timeToLive,
 1515                false, // async
 1516                cancellationToken)
 1517                .EnsureCompleted();
 1518
 1519        /// <summary>
 1520        /// Adds a new message to the back of a queue. The visibility timeout specifies how long the message should be i
 1521        /// to Dequeue and Peek operations. The message content must be a UTF-8 encoded string that is up to 64KB in siz
 1522        ///
 1523        /// For more information, see
 1524        /// <see href="https://docs.microsoft.com/rest/api/storageservices/put-message">
 1525        /// Put Message</see>.
 1526        /// </summary>
 1527        /// <param name="messageText">
 1528        /// Message text.
 1529        /// </param>
 1530        /// <param name="visibilityTimeout">
 1531        /// Visibility timeout.  Optional with a default value of 0.  Cannot be larger than 7 days.
 1532        /// </param>
 1533        /// <param name="timeToLive">
 1534        /// Optional. Specifies the time-to-live interval for the message
 1535        /// </param>
 1536        /// <param name="cancellationToken">
 1537        /// Optional <see cref="CancellationToken"/>.
 1538        /// </param>
 1539        /// <returns>
 1540        /// <see cref="Response{SendReceipt}"/>
 1541        /// </returns>
 1542        public virtual async Task<Response<SendReceipt>> SendMessageAsync(
 1543            string messageText,
 1544            TimeSpan? visibilityTimeout = default,
 1545            TimeSpan? timeToLive = default,
 1546            CancellationToken cancellationToken = default) =>
 1547            await SendMessageInternal(
 1548                messageText,
 1549                visibilityTimeout,
 1550                timeToLive,
 1551                true, // async
 1552                cancellationToken)
 1553                .ConfigureAwait(false);
 1554
 1555        /// <summary>
 1556        /// Adds a new message to the back of a queue. The visibility timeout specifies how long the message should be i
 1557        /// to Dequeue and Peek operations. The message content must be a UTF-8 encoded string that is up to 64KB in siz
 1558        ///
 1559        /// For more information, see
 1560        /// <see href="https://docs.microsoft.com/rest/api/storageservices/put-message">
 1561        /// Put Message</see>.
 1562        /// </summary>
 1563        /// <param name="messageText">
 1564        /// Message text.
 1565        /// </param>
 1566        /// <param name="visibilityTimeout">
 1567        /// Visibility timeout.  Optional with a default value of 0.  Cannot be larger than 7 days.
 1568        /// </param>
 1569        /// <param name="timeToLive">
 1570        /// Optional. Specifies the time-to-live interval for the message
 1571        /// </param>
 1572        /// <param name="async">
 1573        /// Whether to invoke the operation asynchronously.
 1574        /// </param>
 1575        /// <param name="cancellationToken">
 1576        /// Optional <see cref="CancellationToken"/>.
 1577        /// </param>
 1578        /// <returns>
 1579        /// <see cref="Response{SendMessageResult}"/>
 1580        /// </returns>
 1581        private async Task<Response<SendReceipt>> SendMessageInternal(
 1582            string messageText,
 1583            TimeSpan? visibilityTimeout,
 1584            TimeSpan? timeToLive,
 1585            bool async,
 1586            CancellationToken cancellationToken)
 1587        {
 1588            using (Pipeline.BeginLoggingScope(nameof(QueueClient)))
 1589            {
 1590                Pipeline.LogMethodEnter(
 1591                    nameof(QueueClient),
 1592                    message:
 1593                    $"Uri: {MessagesUri}\n" +
 1594                    $"{nameof(visibilityTimeout)}: {visibilityTimeout}\n" +
 1595                    $"{nameof(timeToLive)}: {timeToLive}");
 1596                try
 1597                {
 1598                    messageText = UsingClientSideEncryption
 1599                        ? await new QueueClientSideEncryptor(new ClientSideEncryptor(ClientSideEncryption))
 1600                            .ClientSideEncryptInternal(messageText, async, cancellationToken).ConfigureAwait(false)
 1601                        : messageText;
 1602
 1603                    Response<IEnumerable<SendReceipt>> messages =
 1604                        await QueueRestClient.Messages.EnqueueAsync(
 1605                            ClientDiagnostics,
 1606                            Pipeline,
 1607                            MessagesUri,
 1608                            message: new QueueSendMessage { MessageText = messageText },
 1609                            version: Version.ToVersionString(),
 1610                            visibilitytimeout: (int?)visibilityTimeout?.TotalSeconds,
 1611                            messageTimeToLive: (int?)timeToLive?.TotalSeconds,
 1612                            async: async,
 1613                            operationName: $"{nameof(QueueClient)}.{nameof(SendMessage)}",
 1614                            cancellationToken: cancellationToken)
 1615                            .ConfigureAwait(false);
 1616                    // The service returns a sequence of messages, but the
 1617                    // sequence only ever has one value so we'll unwrap it
 1618                    return Response.FromValue(messages.Value.FirstOrDefault(), messages.GetRawResponse());
 1619                }
 1620                catch (Exception ex)
 1621                {
 1622                    Pipeline.LogException(ex);
 1623                    throw;
 1624                }
 1625                finally
 1626                {
 1627                    Pipeline.LogMethodExit(nameof(QueueClient));
 1628                }
 1629            }
 1630        }
 1631        #endregion SendMessage
 1632
 1633        #region ReceiveMessages
 1634        /// <summary>
 1635        /// Receives one or more messages from the front of the queue.
 1636        ///
 1637        /// For more information, see
 1638        /// <see href="https://docs.microsoft.com/rest/api/storageservices/get-messages">
 1639        /// Get Messages</see>.
 1640        /// </summary>
 1641        /// <returns>
 1642        /// <see cref="Response{T}"/> where T is an array of <see cref="QueueMessage"/>
 1643        /// </returns>
 1644        public virtual Response<QueueMessage[]> ReceiveMessages() => ReceiveMessages(null); // Pass anything else so we 
 1645
 1646        /// <summary>
 1647        /// Retrieves one or more messages from the front of the queue.
 1648        ///
 1649        /// For more information, see
 1650        /// <see href="https://docs.microsoft.com/rest/api/storageservices/get-messages">
 1651        /// Get Messages</see>.
 1652        /// </summary>
 1653        /// <returns>
 1654        /// <see cref="Response{T}"/> where T is an array of <see cref="QueueMessage"/>
 1655        /// </returns>
 1656        public virtual async Task<Response<QueueMessage[]>> ReceiveMessagesAsync() =>
 1657            await ReceiveMessagesAsync(null)  // Pass anything else so we don't recurse on this overload
 1658            .ConfigureAwait(false);
 1659
 1660        /// <summary>
 1661        /// Receives one or more messages from the front of the queue.
 1662        ///
 1663        /// For more information, see
 1664        /// <see href="https://docs.microsoft.com/rest/api/storageservices/get-messages">
 1665        /// Get Messages</see>.
 1666        /// </summary>
 1667        /// <param name="cancellationToken">
 1668        /// Optional <see cref="CancellationToken"/>
 1669        /// </param>
 1670        /// <returns>
 1671        /// <see cref="Response{T}"/> where T is an array of <see cref="QueueMessage"/>
 1672        /// </returns>
 1673        public virtual Response<QueueMessage[]> ReceiveMessages(CancellationToken cancellationToken = default) =>
 1674            ReceiveMessages(
 1675                cancellationToken: cancellationToken,
 1676                visibilityTimeout: null); // Pass anything else so we don't recurse on this overload
 1677
 1678        /// <summary>
 1679        /// Retrieves one or more messages from the front of the queue.
 1680        ///
 1681        /// For more information, see
 1682        /// <see href="https://docs.microsoft.com/rest/api/storageservices/get-messages">
 1683        /// Get Messages</see>.
 1684        /// </summary>
 1685        /// <param name="cancellationToken">
 1686        /// Optional <see cref="CancellationToken"/>
 1687        /// </param>
 1688        /// <returns>
 1689        /// <see cref="Response{T}"/> where T is an array of <see cref="QueueMessage"/>
 1690        /// </returns>
 1691        public virtual async Task<Response<QueueMessage[]>> ReceiveMessagesAsync(CancellationToken cancellationToken = d
 1692            await ReceiveMessagesAsync(
 1693                cancellationToken: cancellationToken,
 1694                visibilityTimeout: null) // Pass anything else so we don't recurse on this overload
 1695            .ConfigureAwait(false);
 1696
 1697        /// <summary>
 1698        /// Receives one or more messages from the front of the queue.
 1699        ///
 1700        /// For more information, see
 1701        /// <see href="https://docs.microsoft.com/rest/api/storageservices/get-messages">
 1702        /// Get Messages</see>.
 1703        /// </summary>
 1704        /// <param name="maxMessages">
 1705        /// Optional. A nonzero integer value that specifies the number of messages to retrieve from the queue, up to a 
 1706        /// If fewer are visible, the visible messages are returned. By default, a single message is retrieved from the 
 1707        /// </param>
 1708        /// <param name="visibilityTimeout">
 1709        /// Optional. Specifies the new visibility timeout value, in seconds, relative to server time. The default value
 1710        /// </param>
 1711        /// <param name="cancellationToken">
 1712        /// Optional <see cref="CancellationToken"/>
 1713        /// </param>
 1714        /// <returns>
 1715        /// <see cref="Response{T}"/> where T is an array of <see cref="QueueMessage"/>
 1716        /// </returns>
 1717        public virtual Response<QueueMessage[]> ReceiveMessages(
 1718            int? maxMessages = default,
 1719            TimeSpan? visibilityTimeout = default,
 1720            CancellationToken cancellationToken = default) =>
 1721            ReceiveMessagesInternal(
 1722                maxMessages,
 1723                visibilityTimeout,
 1724                false, // async
 1725                cancellationToken)
 1726                .EnsureCompleted();
 1727
 1728        /// <summary>
 1729        /// Retrieves one or more messages from the front of the queue.
 1730        ///
 1731        /// For more information, see
 1732        /// <see href="https://docs.microsoft.com/rest/api/storageservices/get-messages">
 1733        /// Get Messages</see>.
 1734        /// </summary>
 1735        /// <param name="maxMessages">
 1736        /// Optional. A nonzero integer value that specifies the number of messages to retrieve from the queue, up to a 
 1737        /// If fewer are visible, the visible messages are returned. By default, a single message is retrieved from the 
 1738        /// </param>
 1739        /// <param name="visibilityTimeout">
 1740        /// Optional. Specifies the new visibility timeout value, in seconds, relative to server time. The default value
 1741        /// </param>
 1742        /// <param name="cancellationToken">
 1743        /// Optional <see cref="CancellationToken"/>
 1744        /// </param>
 1745        /// <returns>
 1746        /// <see cref="Response{T}"/> where T is an array of <see cref="QueueMessage"/>
 1747        /// </returns>
 1748        public virtual async Task<Response<QueueMessage[]>> ReceiveMessagesAsync(
 1749            int? maxMessages = default,
 1750            TimeSpan? visibilityTimeout = default,
 1751            CancellationToken cancellationToken = default) =>
 1752            await ReceiveMessagesInternal(
 1753                maxMessages,
 1754                visibilityTimeout,
 1755                true, // async
 1756                cancellationToken)
 1757                .ConfigureAwait(false);
 1758
 1759        /// <summary>
 1760        /// Retrieves one or more messages from the front of the queue.
 1761        ///
 1762        /// For more information, see
 1763        /// <see href="https://docs.microsoft.com/rest/api/storageservices/get-messages">
 1764        /// Get Messages</see>.
 1765        /// </summary>
 1766        /// <param name="maxMessages">
 1767        /// Optional. A nonzero integer value that specifies the number of messages to retrieve from the queue, up to a 
 1768        /// If fewer are visible, the visible messages are returned. By default, a single message is retrieved from the 
 1769        /// </param>
 1770        /// <param name="visibilityTimeout">
 1771        /// Optional. Specifies the new visibility timeout value, in seconds, relative to server time. The default value
 1772        /// </param>
 1773        /// <param name="async">
 1774        /// Whether to invoke the operation asynchronously.
 1775        /// </param>
 1776        /// <param name="cancellationToken">
 1777        /// Optional <see cref="CancellationToken"/>
 1778        /// </param>
 1779        /// <returns>
 1780        /// <see cref="Response{T}"/> where T is an array of <see cref="QueueMessage"/>
 1781        /// </returns>
 1782        private async Task<Response<QueueMessage[]>> ReceiveMessagesInternal(
 1783            int? maxMessages,
 1784            TimeSpan? visibilityTimeout,
 1785            bool async,
 1786            CancellationToken cancellationToken)
 1787        {
 1788            using (Pipeline.BeginLoggingScope(nameof(QueueClient)))
 1789            {
 1790                Pipeline.LogMethodEnter(
 1791                    nameof(QueueClient),
 1792                    message:
 1793                    $"Uri: {MessagesUri}\n" +
 1794                    $"{nameof(maxMessages)}: {maxMessages}\n" +
 1795                    $"{nameof(visibilityTimeout)}: {visibilityTimeout}");
 1796                try
 1797                {
 1798                    var response = await QueueRestClient.Messages.DequeueAsync(
 1799                        ClientDiagnostics,
 1800                        Pipeline,
 1801                        MessagesUri,
 1802                        version: Version.ToVersionString(),
 1803                        numberOfMessages: maxMessages,
 1804                        visibilitytimeout: (int?)visibilityTimeout?.TotalSeconds,
 1805                        async: async,
 1806                        operationName: $"{nameof(QueueClient)}.{nameof(ReceiveMessages)}",
 1807                        cancellationToken: cancellationToken)
 1808                        .ConfigureAwait(false);
 1809
 1810                    // Return an exploding Response on 304
 1811                    if (response.IsUnavailable())
 1812                    {
 1813                        return response.GetRawResponse().AsNoBodyResponse<QueueMessage[]>();
 1814                    }
 1815                    else if (UsingClientSideEncryption)
 1816                    {
 1817                        return Response.FromValue(
 1818                            await new QueueClientSideDecryptor(ClientSideEncryption)
 1819                                .ClientSideDecryptMessagesInternal(response.Value.ToArray(), async, cancellationToken).C
 1820                            response.GetRawResponse());
 1821                    }
 1822                    else
 1823                    {
 1824                        return Response.FromValue(response.Value.ToArray(), response.GetRawResponse());
 1825                    }
 1826                }
 1827                catch (Exception ex)
 1828                {
 1829                    Pipeline.LogException(ex);
 1830                    throw;
 1831                }
 1832                finally
 1833                {
 1834                    Pipeline.LogMethodExit(nameof(QueueClient));
 1835                }
 1836            }
 1837        }
 1838        #endregion ReceiveMessages
 1839
 1840        #region PeekMessages
 1841        /// <summary>
 1842        /// Retrieves one or more messages from the front of the queue but does not alter the visibility of the message.
 1843        ///
 1844        /// For more information, see
 1845        /// <see href="https://docs.microsoft.com/rest/api/storageservices/peek-messages">
 1846        /// Peek Messages</see>.
 1847        /// </summary>
 1848        /// <param name="maxMessages">
 1849        /// Optional. A nonzero integer value that specifies the number of messages to peek from the queue, up to a maxi
 1850        /// By default, a single message is peeked from the queue with this operation.
 1851        /// </param>
 1852        /// <param name="cancellationToken">
 1853        /// Optional <see cref="CancellationToken"/>
 1854        /// </param>
 1855        /// <returns>
 1856        /// <see cref="Response{T}"/> where T is an array of <see cref="PeekedMessage"/>
 1857        /// </returns>
 1858        public virtual Response<PeekedMessage[]> PeekMessages(
 1859            int? maxMessages = default,
 1860            CancellationToken cancellationToken = default) =>
 1861            PeekMessagesInternal(
 1862                maxMessages,
 1863                false, // async
 1864                cancellationToken)
 1865                .EnsureCompleted();
 1866
 1867        /// <summary>
 1868        /// Retrieves one or more messages from the front of the queue but does not alter the visibility of the message.
 1869        ///
 1870        /// For more information, see
 1871        /// <see href="https://docs.microsoft.com/rest/api/storageservices/peek-messages">
 1872        /// Peek Messages</see>.
 1873        /// </summary>
 1874        /// <param name="maxMessages">
 1875        /// Optional. A nonzero integer value that specifies the number of messages to peek from the queue, up to a maxi
 1876        /// By default, a single message is peeked from the queue with this operation.
 1877        /// </param>
 1878        /// <param name="cancellationToken">
 1879        /// Optional <see cref="CancellationToken"/>
 1880        /// </param>
 1881        /// <returns>
 1882        /// <see cref="Response{T}"/> where T is an array of <see cref="PeekedMessage"/>
 1883        /// </returns>
 1884        public virtual async Task<Response<PeekedMessage[]>> PeekMessagesAsync(
 1885            int? maxMessages = default,
 1886            CancellationToken cancellationToken = default) =>
 1887            await PeekMessagesInternal(
 1888                maxMessages,
 1889                true, // async
 1890                cancellationToken)
 1891                .ConfigureAwait(false);
 1892
 1893        /// <summary>
 1894        /// Retrieves one or more messages from the front of the queue but does not alter the visibility of the message.
 1895        ///
 1896        /// For more information, see
 1897        /// <see href="https://docs.microsoft.com/rest/api/storageservices/peek-messages">
 1898        /// Peek Messages</see>.
 1899        /// </summary>
 1900        /// <param name="maxMessages">
 1901        /// Optional. A nonzero integer value that specifies the number of messages to peek from the queue, up to a maxi
 1902        /// By default, a single message is peeked from the queue with this operation.
 1903        /// </param>
 1904        /// <param name="async">
 1905        /// Whether to invoke the operation asynchronously.
 1906        /// </param>
 1907        /// <param name="cancellationToken">
 1908        /// Optional <see cref="CancellationToken"/>
 1909        /// </param>
 1910        /// <returns>
 1911        /// <see cref="Response{T}"/> where T is an array of <see cref="PeekedMessage"/>
 1912        /// </returns>
 1913        private async Task<Response<PeekedMessage[]>> PeekMessagesInternal(
 1914            int? maxMessages,
 1915            bool async,
 1916            CancellationToken cancellationToken)
 1917        {
 1918            using (Pipeline.BeginLoggingScope(nameof(QueueClient)))
 1919            {
 1920                Pipeline.LogMethodEnter(
 1921                    nameof(QueueClient),
 1922                    message:
 1923                    $"Uri: {MessagesUri}\n" +
 1924                    $"{nameof(maxMessages)}: {maxMessages}");
 1925                try
 1926                {
 1927                    Response<IEnumerable<PeekedMessage>> response = await QueueRestClient.Messages.PeekAsync(
 1928                        ClientDiagnostics,
 1929                        Pipeline,
 1930                        MessagesUri,
 1931                        version: Version.ToVersionString(),
 1932                        numberOfMessages: maxMessages,
 1933                        async: async,
 1934                        operationName: $"{nameof(QueueClient)}.{nameof(PeekMessages)}",
 1935                        cancellationToken: cancellationToken)
 1936                        .ConfigureAwait(false);
 1937
 1938                    // Return an exploding Response on 304
 1939                    if (response.IsUnavailable())
 1940                    {
 1941                        return response.GetRawResponse().AsNoBodyResponse<PeekedMessage[]>();
 1942                    }
 1943                    else if (UsingClientSideEncryption)
 1944                    {
 1945                        return Response.FromValue(
 1946                            await new QueueClientSideDecryptor(ClientSideEncryption)
 1947                                .ClientSideDecryptMessagesInternal(response.Value.ToArray(), async, cancellationToken).C
 1948                            response.GetRawResponse());
 1949                    }
 1950                    else
 1951                    {
 1952                        return Response.FromValue(response.Value.ToArray(), response.GetRawResponse());
 1953                    }
 1954                }
 1955                catch (Exception ex)
 1956                {
 1957                    Pipeline.LogException(ex);
 1958                    throw;
 1959                }
 1960                finally
 1961                {
 1962                    Pipeline.LogMethodExit(nameof(QueueClient));
 1963                }
 1964            }
 1965        }
 1966        #endregion PeekMessages
 1967
 1968        /// <summary>
 1969        /// Get the URI to a specific message given its ID.
 1970        /// </summary>
 1971        /// <param name="messageId">ID of the message.</param>
 1972        /// <returns>URI to the given message.</returns>
 1973        private Uri GetMessageUri(string messageId) =>
 1974            MessagesUri.AppendToPath(messageId.ToString(CultureInfo.InvariantCulture));
 1975
 1976        #region DeleteMessage
 1977        /// <summary>
 1978        /// Permanently removes the specified message from its queue.
 1979        ///
 1980        /// For more information, see
 1981        /// <see href="https://docs.microsoft.com/rest/api/storageservices/delete-message2">
 1982        /// Delete Message</see>.
 1983        /// </summary>
 1984        /// <param name="messageId">ID of the message to delete.</param>
 1985        /// <param name="popReceipt">
 1986        /// Required. A valid pop receipt value returned from an earlier call to the Get Messages or Update Message oper
 1987        /// </param>
 1988        /// <param name="cancellationToken">
 1989        /// Optional <see cref="CancellationToken"/>.
 1990        /// </param>
 1991        /// <returns>
 1992        /// <see cref="Response"/>.
 1993        /// </returns>
 1994        public virtual Response DeleteMessage(
 1995            string messageId,
 1996            string popReceipt,
 1997            CancellationToken cancellationToken = default) =>
 1998            DeleteMessageInternal(
 1999                messageId,
 2000                popReceipt,
 2001                false, // async
 2002                cancellationToken)
 2003                .EnsureCompleted();
 2004
 2005        /// <summary>
 2006        /// Permanently removes the specified message from its queue.
 2007        ///
 2008        /// For more information, see
 2009        /// <see href="https://docs.microsoft.com/rest/api/storageservices/delete-message2">
 2010        /// Delete Message</see>.
 2011        /// </summary>
 2012        /// <param name="messageId">ID of the message to delete.</param>
 2013        /// <param name="popReceipt">
 2014        /// Required. A valid pop receipt value returned from an earlier call to the Get Messages or Update Message oper
 2015        /// </param>
 2016        /// <param name="cancellationToken">
 2017        /// Optional <see cref="CancellationToken"/>.
 2018        /// </param>
 2019        /// <returns>
 2020        /// <see cref="Response"/>.
 2021        /// </returns>
 2022        public virtual async Task<Response> DeleteMessageAsync(
 2023            string messageId,
 2024            string popReceipt,
 2025            CancellationToken cancellationToken = default) =>
 2026            await DeleteMessageInternal(
 2027                messageId,
 2028                popReceipt,
 2029                true, // async
 2030                cancellationToken)
 2031                .ConfigureAwait(false);
 2032
 2033        /// <summary>
 2034        /// Permanently removes the specified message from its queue.
 2035        ///
 2036        /// For more information, see
 2037        /// <see href="https://docs.microsoft.com/rest/api/storageservices/delete-message2">
 2038        /// Delete Message</see>.
 2039        /// </summary>
 2040        /// <param name="messageId">ID of the message to delete.</param>
 2041        /// <param name="popReceipt">
 2042        /// Required. A valid pop receipt value returned from an earlier call to the Get Messages or Update Message oper
 2043        /// </param>
 2044        /// <param name="async">
 2045        /// Whether to invoke the operation asynchronously.
 2046        /// </param>
 2047        /// <param name="cancellationToken">
 2048        /// Optional <see cref="CancellationToken"/>.
 2049        /// </param>
 2050        /// <returns>
 2051        /// <see cref="Response"/>.
 2052        /// </returns>
 2053        private async Task<Response> DeleteMessageInternal(
 2054            string messageId,
 2055            string popReceipt,
 2056            bool async,
 2057            CancellationToken cancellationToken)
 2058        {
 2059            Uri uri = GetMessageUri(messageId);
 2060            using (Pipeline.BeginLoggingScope(nameof(QueueClient)))
 2061            {
 2062                Pipeline.LogMethodEnter(
 2063                    nameof(QueueClient),
 2064                    message:
 2065                    $"Uri: {uri}\n" +
 2066                    $"{nameof(popReceipt)}: {popReceipt}");
 2067                try
 2068                {
 2069                    return await QueueRestClient.MessageId.DeleteAsync(
 2070                        ClientDiagnostics,
 2071                        Pipeline,
 2072                        uri,
 2073                        popReceipt: popReceipt,
 2074                        version: Version.ToVersionString(),
 2075                        async: async,
 2076                        operationName: $"{nameof(QueueClient)}.{nameof(DeleteMessage)}",
 2077                        cancellationToken: cancellationToken)
 2078                        .ConfigureAwait(false);
 2079                }
 2080                catch (Exception ex)
 2081                {
 2082                    Pipeline.LogException(ex);
 2083                    throw;
 2084                }
 2085                finally
 2086                {
 2087                    Pipeline.LogMethodExit(nameof(QueueClient));
 2088                }
 2089            }
 2090        }
 2091        #endregion DeleteMessage
 2092
 2093        #region UpdateMessage
 2094        /// <summary>
 2095        /// Changes a message's visibility timeout and contents. The message content must be a UTF-8 encoded string that
 2096        ///
 2097        /// For more information, see
 2098        /// <see href="https://docs.microsoft.com/rest/api/storageservices/update-message">
 2099        /// Update Message</see>.
 2100        /// </summary>
 2101        /// <param name="messageId">ID of the message to update.</param>
 2102        /// <param name="popReceipt">
 2103        /// Required. Specifies the valid pop receipt value returned from an earlier call to the Get Messages or Update 
 2104        /// </param>
 2105        /// <param name="messageText">
 2106        /// Optional. Updated message text.
 2107        /// </param>
 2108        /// <param name="visibilityTimeout">
 2109        /// Required. Specifies the new visibility timeout value, in seconds, relative to server time. The new value mus
 2110        /// or equal to 0, and cannot be larger than 7 days. The visibility timeout of a message cannot be set to a valu
 2111        /// expiry time. A message can be updated until it has been deleted or has expired.
 2112        /// </param>
 2113        /// <param name="cancellationToken">
 2114        /// Optional <see cref="CancellationToken"/>.
 2115        /// </param>
 2116        /// <returns>
 2117        /// <see cref="Response{UpdateReceipt}"/>.
 2118        /// </returns>
 2119        public virtual Response<UpdateReceipt> UpdateMessage(
 2120            string messageId,
 2121            string popReceipt,
 2122            string messageText = null,
 2123            TimeSpan visibilityTimeout = default,
 2124            CancellationToken cancellationToken = default) =>
 2125            UpdateMessageInternal(
 2126                messageText,
 2127                messageId,
 2128                popReceipt,
 2129                visibilityTimeout,
 2130                false, // async
 2131                cancellationToken)
 2132                .EnsureCompleted();
 2133
 2134        /// <summary>
 2135        /// Changes a message's visibility timeout and contents. The message content must be a UTF-8 encoded string that
 2136        ///
 2137        /// For more information, see
 2138        /// <see href="https://docs.microsoft.com/rest/api/storageservices/update-message">
 2139        /// Update Message</see>.
 2140        /// </summary>
 2141        /// <param name="messageId">ID of the message to update.</param>
 2142        /// <param name="popReceipt">
 2143        /// Required. Specifies the valid pop receipt value returned from an earlier call to the Get Messages or Update 
 2144        /// </param>
 2145        /// <param name="messageText">
 2146        /// Optional. Updated message text.
 2147        /// </param>
 2148        /// <param name="visibilityTimeout">
 2149        /// Required. Specifies the new visibility timeout value, in seconds, relative to server time. The new value mus
 2150        /// or equal to 0, and cannot be larger than 7 days. The visibility timeout of a message cannot be set to a valu
 2151        /// expiry time. A message can be updated until it has been deleted or has expired.
 2152        /// </param>
 2153        /// <param name="cancellationToken">
 2154        /// Optional <see cref="CancellationToken"/>.
 2155        /// </param>
 2156        /// <returns>
 2157        /// <see cref="Response{UpdateReceipt}"/>.
 2158        /// </returns>
 2159        public virtual async Task<Response<UpdateReceipt>> UpdateMessageAsync(
 2160            string messageId,
 2161            string popReceipt,
 2162            string messageText = null,
 2163            TimeSpan visibilityTimeout = default,
 2164            CancellationToken cancellationToken = default) =>
 2165            await UpdateMessageInternal(
 2166                messageText,
 2167                messageId,
 2168                popReceipt,
 2169                visibilityTimeout,
 2170                true, // async
 2171                cancellationToken)
 2172                .ConfigureAwait(false);
 2173
 2174        /// <summary>
 2175        /// Changes a message's visibility timeout and contents. The message content must be a UTF-8 encoded string that
 2176        ///
 2177        /// For more information, see
 2178        /// <see href="https://docs.microsoft.com/rest/api/storageservices/update-message">
 2179        /// Update Message</see>.
 2180        /// </summary>
 2181        /// <param name="messageText">
 2182        /// Updated message text.
 2183        /// </param>
 2184        /// <param name="messageId">ID of the message to update.</param>
 2185        /// <param name="popReceipt">
 2186        /// Required. Specifies the valid pop receipt value returned from an earlier call to the Get Messages or Update 
 2187        /// </param>
 2188        /// <param name="visibilityTimeout">
 2189        /// Required. Specifies the new visibility timeout value, in seconds, relative to server time. The new value mus
 2190        /// or equal to 0, and cannot be larger than 7 days. The visibility timeout of a message cannot be set to a valu
 2191        /// expiry time. A message can be updated until it has been deleted or has expired.
 2192        /// </param>
 2193        /// <param name="async">
 2194        /// Whether to invoke the operation asynchronously.
 2195        /// </param>
 2196        /// <param name="cancellationToken">
 2197        /// Optional <see cref="CancellationToken"/>.
 2198        /// </param>
 2199        /// <returns>
 2200        /// <see cref="Response{UpdateReceipt}"/>.
 2201        /// </returns>
 2202        private async Task<Response<UpdateReceipt>> UpdateMessageInternal(
 2203            string messageText,
 2204            string messageId,
 2205            string popReceipt,
 2206            TimeSpan visibilityTimeout,
 2207            bool async,
 2208            CancellationToken cancellationToken)
 2209        {
 2210            Uri uri = GetMessageUri(messageId);
 2211            using (Pipeline.BeginLoggingScope(nameof(QueueClient)))
 2212            {
 2213                Pipeline.LogMethodEnter(
 2214                    nameof(QueueClient),
 2215                    message:
 2216                    $"Uri: {uri}\n" +
 2217                    $"{nameof(popReceipt)}: {popReceipt}" +
 2218                    $"{nameof(visibilityTimeout)}: {visibilityTimeout}");
 2219                try
 2220                {
 2221                    messageText = UsingClientSideEncryption && messageText != default
 2222                        ? await new QueueClientSideEncryptor(new ClientSideEncryptor(ClientSideEncryption))
 2223                            .ClientSideEncryptInternal(messageText, async, cancellationToken).ConfigureAwait(false)
 2224                        : messageText;
 2225
 2226                    return await QueueRestClient.MessageId.UpdateAsync(
 2227                        ClientDiagnostics,
 2228                        Pipeline,
 2229                        uri,
 2230                        message: new QueueSendMessage { MessageText = messageText },
 2231                        popReceipt: popReceipt,
 2232                        visibilitytimeout: (int)visibilityTimeout.TotalSeconds,
 2233                        version: Version.ToVersionString(),
 2234                        async: async,
 2235                        operationName: $"{nameof(QueueClient)}.{nameof(UpdateMessage)}",
 2236                        cancellationToken: cancellationToken)
 2237                        .ConfigureAwait(false);
 2238                }
 2239                catch (Exception ex)
 2240                {
 2241                    Pipeline.LogException(ex);
 2242                    throw;
 2243                }
 2244                finally
 2245                {
 2246                    Pipeline.LogMethodExit(nameof(QueueClient));
 2247                }
 2248            }
 2249        }
 2250        #endregion UpdateMessage
 2251    }
 2252}
 2253
 2254namespace Azure.Storage.Queues.Specialized
 2255{
 2256    /// <summary>
 2257    /// Add methods to <see cref="Queues"/> clients.
 2258    /// </summary>
 2259    public static partial class SpecializedQueueExtensions
 2260    {
 2261        /// <summary>
 2262        /// Creates a new instance of the <see cref="QueueClient"/> class, maintaining all the same
 2263        /// internals but specifying new <see cref="ClientSideEncryptionOptions"/>.
 2264        /// </summary>
 2265        /// <param name="client">Client to base off of.</param>
 2266        /// <param name="clientSideEncryptionOptions">New encryption options. Setting this to <code>default</code> will 
 2267        /// <returns>New instance with provided options and same internals otherwise.</returns>
 2268        public static QueueClient WithClientSideEncryptionOptions(this QueueClient client, ClientSideEncryptionOptions c
 02269            => new QueueClient(
 02270                client.Uri,
 02271                client.Pipeline,
 02272                client.Version,
 02273                client.ClientDiagnostics,
 02274                clientSideEncryptionOptions);
 2275    }
 2276}