< Summary

Class:Microsoft.Azure.ServiceBus.ServiceBusConnectionStringBuilder
Assembly:Microsoft.Azure.ServiceBus
File(s):C:\Git\azure-sdk-for-net\sdk\servicebus\Microsoft.Azure.ServiceBus\src\ServiceBusConnectionStringBuilder.cs
Covered lines:89
Uncovered lines:32
Coverable lines:121
Total lines:426
Line coverage:73.5% (89 of 121)
Covered branches:60
Total branches:78
Branch coverage:76.9% (60 of 78)

Metrics

MethodCyclomatic complexity Line coverage Branch coverage
.ctor()-57.14%50%
.ctor(...)-100%100%
.ctor(...)-80%37.5%
.ctor(...)-0%0%
.ctor(...)-0%100%
.ctor(...)-0%100%
get_Endpoint()-100%100%
set_Endpoint(...)-100%100%
get_EntityPath()-100%100%
set_EntityPath(...)-100%100%
get_SasKeyName()-100%100%
set_SasKeyName(...)-100%100%
get_SasKey()-100%100%
set_SasKey(...)-100%100%
get_SasToken()-100%100%
set_SasToken(...)-100%100%
get_TransportType()-100%100%
get_OperationTimeout()-0%100%
get_Authentication()-100%100%
set_Authentication(...)-0%0%
GetNamespaceConnectionString()-93.75%92.86%
GetEntityConnectionString()-66.67%50%
ToString()-100%100%
ParseConnectionString(...)-91.67%91.18%

File(s)

C:\Git\azure-sdk-for-net\sdk\servicebus\Microsoft.Azure.ServiceBus\src\ServiceBusConnectionStringBuilder.cs

#LineLine coverage
 1// Copyright (c) Microsoft. All rights reserved.
 2// Licensed under the MIT license. See LICENSE file in the project root for full license information.
 3
 4namespace Microsoft.Azure.ServiceBus
 5{
 6    using System;
 7    using System.Collections.Generic;
 8    using System.Globalization;
 9    using System.Text;
 10    using Primitives;
 11
 12    /// <summary>
 13    /// Used to generate Service Bus connection strings.
 14    /// </summary>
 15    public class ServiceBusConnectionStringBuilder
 16    {
 17        const char KeyValueSeparator = '=';
 18        const char KeyValuePairDelimiter = ';';
 19        const string EndpointScheme = "amqps";
 20        const string EndpointConfigName = "Endpoint";
 21        const string SharedAccessKeyNameConfigName = "SharedAccessKeyName";
 22        const string SharedAccessKeyConfigName = "SharedAccessKey";
 23        const string SharedAccessSignatureConfigName = "SharedAccessSignature";
 24        const string AuthenticationConfigName = "Authentication";
 25
 26        const string EntityPathConfigName = "EntityPath";
 27        const string TransportTypeConfigName = "TransportType";
 28
 29        const string OperationTimeoutConfigName = "OperationTimeout";
 30
 31        string entityPath, sasKeyName, sasKey, sasToken, endpoint;
 32        AuthenticationType authType = AuthenticationType.Other;
 33
 34        public enum AuthenticationType
 35        {
 36            Other,
 37            ManagedIdentity
 38        }
 39
 40        /// <summary>
 41        /// Instantiates a new <see cref="ServiceBusConnectionStringBuilder"/>
 42        /// </summary>
 2043        public ServiceBusConnectionStringBuilder()
 44        {
 2045        }
 46
 47        /// <summary>
 48        /// Instantiates a new <see cref="ServiceBusConnectionStringBuilder"/>.
 49        /// </summary>
 50        /// <param name="connectionString">Connection string for namespace or the entity.</param>
 5851        public ServiceBusConnectionStringBuilder(string connectionString)
 52        {
 5853            if (!string.IsNullOrWhiteSpace(connectionString))
 54            {
 5855                this.ParseConnectionString(connectionString);
 56            }
 5257        }
 58
 59        /// <summary>
 60        /// Instantiates a new <see cref="ServiceBusConnectionStringBuilder"/>.
 61        /// </summary>
 62        /// <example>
 63        /// <code>
 64        /// var connectionStringBuilder = new ServiceBusConnectionStringBuilder(
 65        ///     "contoso.servicebus.windows.net",
 66        ///     "myQueue",
 67        ///     "RootManageSharedAccessKey",
 68        ///     "&amp;lt;sharedAccessKey&amp;gt;
 69        /// );
 70        /// </code>
 71        /// </example>
 72        /// <param name="endpoint">Fully qualified endpoint.</param>
 673        public ServiceBusConnectionStringBuilder(string endpoint, string entityPath, string sharedAccessKeyName, string 
 74        {
 675            if (string.IsNullOrWhiteSpace(endpoint))
 76            {
 077                throw Fx.Exception.ArgumentNullOrWhiteSpace(nameof(endpoint));
 78            }
 679            if (string.IsNullOrWhiteSpace(sharedAccessKeyName) || string.IsNullOrWhiteSpace(sharedAccessKey))
 80            {
 081                throw Fx.Exception.ArgumentNullOrWhiteSpace(string.IsNullOrWhiteSpace(sharedAccessKeyName) ? nameof(shar
 82            }
 83
 684            this.Endpoint = endpoint;
 685            this.EntityPath = entityPath;
 686            this.SasKeyName = sharedAccessKeyName;
 687            this.SasKey = sharedAccessKey;
 688        }
 89
 90        /// <summary>
 91        /// Instantiates a new <see cref="ServiceBusConnectionStringBuilder"/>.
 92        /// </summary>
 93        /// <example>
 94        /// <code>
 95        /// var connectionStringBuilder = new ServiceBusConnectionStringBuilder(
 96        ///     "contoso.servicebus.windows.net",
 97        ///     "myQueue",
 98        ///     "{ ... SAS token ... }"
 99        /// );
 100        /// </code>
 101        /// </example>
 102        /// <param name="endpoint">Fully qualified endpoint.</param>
 0103        public ServiceBusConnectionStringBuilder(string endpoint, string entityPath, string sharedAccessSignature)
 104        {
 0105            if (string.IsNullOrWhiteSpace(endpoint))
 106            {
 0107                throw Fx.Exception.ArgumentNullOrWhiteSpace(nameof(endpoint));
 108            }
 0109            if (string.IsNullOrWhiteSpace(sharedAccessSignature))
 110            {
 0111                throw Fx.Exception.ArgumentNullOrWhiteSpace(nameof(sharedAccessSignature));
 112            }
 113
 0114            this.Endpoint = endpoint;
 0115            this.EntityPath = entityPath;
 0116            this.SasToken = sharedAccessSignature;
 0117        }
 118
 119        /// <summary>
 120        /// Instantiates a new <see cref="T:Microsoft.Azure.ServiceBus.ServiceBusConnectionStringBuilder" />.
 121        /// </summary>
 122        /// <example>
 123        /// <code>
 124        /// var connectionStringBuilder = new ServiceBusConnectionStringBuilder(
 125        ///     "contoso.servicebus.windows.net",
 126        ///     "myQueue",
 127        ///     "RootManageSharedAccessKey",
 128        ///     "&amp;lt;sharedAccessKey&amp;gt;,
 129        ///     TransportType.Amqp
 130        /// );
 131        /// </code>
 132        /// </example>
 133        /// <param name="endpoint">Fully qualified endpoint.</param>
 134        public ServiceBusConnectionStringBuilder(string endpoint, string entityPath, string sharedAccessKeyName, string 
 0135            : this(endpoint, entityPath, sharedAccessKeyName, sharedAccessKey)
 136        {
 0137            this.TransportType = transportType;
 0138        }
 139
 140        /// <summary>
 141        /// Instantiates a new <see cref="ServiceBusConnectionStringBuilder"/>.
 142        /// </summary>
 143        /// <example>
 144        /// <code>
 145        /// var connectionStringBuilder = new ServiceBusConnectionStringBuilder(
 146        ///     "contoso.servicebus.windows.net",
 147        ///     "myQueue",
 148        ///     "{ ... SAS token ... }",
 149        ///     TransportType.Amqp
 150        /// );
 151        /// </code>
 152        /// </example>
 153        /// <param name="endpoint">Fully qualified endpoint.</param>
 154        public ServiceBusConnectionStringBuilder(string endpoint, string entityPath, string sharedAccessSignature, Trans
 0155            :this(endpoint, entityPath, sharedAccessSignature)
 156        {
 0157            this.TransportType = transportType;
 0158        }
 159
 160        /// <summary>
 161        /// Fully qualified domain name of the endpoint.
 162        /// </summary>
 163        /// <example>
 164        /// <code>this.Endpoint = contoso.servicebus.windows.net</code>
 165        /// </example>
 166        /// <exception cref="ArgumentException">Throws when endpoint is not fully qualified endpoint.</exception>
 167        /// <exception cref="UriFormatException">Throws when the hostname cannot be parsed</exception>
 168        public string Endpoint
 169        {
 126170            get => this.endpoint;
 171            set
 172            {
 86173                if (!value.Contains("."))
 174                {
 2175                    throw Fx.Exception.Argument(nameof(Endpoint), "Endpoint should be fully qualified endpoint");
 176                }
 177
 84178                var uriBuilder = new UriBuilder(value.Trim());
 82179                this.endpoint = (value.Contains("://") ? uriBuilder.Scheme : EndpointScheme) + "://" + uriBuilder.Host;
 82180            }
 181        }
 182
 183        /// <summary>
 184        /// Get the entity path value from the connection string
 185        /// </summary>
 186        public string EntityPath
 187        {
 60188            get => this.entityPath;
 18189            set => this.entityPath = value.Trim();
 190        }
 191
 192        /// <summary>
 193        /// Get the shared access policy owner name from the connection string
 194        /// </summary>
 195        public string SasKeyName
 196        {
 100197            get => this.sasKeyName;
 198            set
 199            {
 44200                if (this.Authentication != AuthenticationType.Other)
 201                {
 2202                    throw Fx.Exception.Argument("Authentication, SasKeyName", Resources.ArgumentInvalidCombination.Forma
 203                }
 42204                this.sasKeyName = value.Trim();
 42205            }
 206        }
 207
 208        /// <summary>
 209        /// Get the shared access policy key value from the connection string
 210        /// </summary>
 211        /// <value>Shared Access Signature key</value>
 212        public string SasKey
 213        {
 70214            get => this.sasKey;
 36215            set => this.sasKey = value.Trim();
 216        }
 217
 218         /// <summary>
 219        /// Get the shared access signature token from the connection string
 220        /// </summary>
 221        /// <value>Shared Access Signature token</value>
 222        public string SasToken
 223        {
 74224            get => this.sasToken;
 225            set
 226            {
 4227                if (this.Authentication != AuthenticationType.Other)
 228                {
 2229                    throw Fx.Exception.Argument("Authentication, SasToken", Resources.ArgumentInvalidCombination.FormatF
 230                }
 2231                this.sasToken = value.Trim();
 2232            }
 233        }
 234
 235        /// <summary>
 236        /// Get the transport type from the connection string
 237        /// </summary>
 78238        public TransportType TransportType { get; set; }
 239
 240        /// <summary>
 241        /// Duration after which individual operations will timeout.
 242        /// </summary>
 243        /// <remarks>Defaults to 1 minute.</remarks>
 0244        public TimeSpan OperationTimeout { get; set; } = Constants.DefaultOperationTimeout;
 245
 246        /// <summary>
 247        /// Enables Azure Active Directory Managed Identity authentication when set to ServiceBusConnectionStringBuilder
 248        /// </summary>
 249        public AuthenticationType Authentication
 250        {
 106251            get => this.authType;
 252            set
 253            {
 0254                if (!string.IsNullOrWhiteSpace(this.SasKeyName))
 255                {
 0256                    throw Fx.Exception.Argument(nameof(AuthenticationConfigName) + ", " + nameof(SharedAccessKeyConfigNa
 0257                        Resources.ArgumentInvalidCombination.FormatForUser(nameof(AuthenticationConfigName) + ", " + nam
 258                }
 259
 0260                if (!string.IsNullOrWhiteSpace(this.SasToken))
 261                {
 0262                    throw Fx.Exception.Argument(nameof(AuthenticationConfigName) + ", " + nameof(SharedAccessKeyConfigNa
 0263                        Resources.ArgumentInvalidCombination.FormatForUser(nameof(AuthenticationConfigName) + ", " + nam
 264                }
 0265                this.authType = value;
 0266            }
 267        }
 268
 0269        internal Dictionary<string, string> ConnectionStringProperties = new Dictionary<string, string>(StringComparer.C
 270
 271        /// <summary>
 272        /// Returns an interoperable connection string that can be used to connect to ServiceBus Namespace
 273        /// </summary>
 274        /// <returns>Namespace connection string</returns>
 275        public string GetNamespaceConnectionString()
 276        {
 34277            var connectionStringBuilder = new StringBuilder();
 34278            if (this.Endpoint != null)
 279            {
 34280                connectionStringBuilder.Append(EndpointConfigName).Append(KeyValueSeparator).Append(this.Endpoint).Appen
 281            }
 282
 34283            if (!string.IsNullOrWhiteSpace(this.SasKeyName))
 284            {
 14285                connectionStringBuilder.Append(SharedAccessKeyNameConfigName).Append(KeyValueSeparator).Append(this.SasK
 286            }
 287
 34288            if (!string.IsNullOrWhiteSpace(this.SasKey))
 289            {
 10290                connectionStringBuilder.Append(SharedAccessKeyConfigName).Append(KeyValueSeparator).Append(this.SasKey).
 291            }
 292
 34293            if (!string.IsNullOrWhiteSpace(this.SasToken))
 294            {
 0295                connectionStringBuilder.Append(SharedAccessSignatureConfigName).Append(KeyValueSeparator).Append(this.Sa
 296            }
 297
 34298            if (this.TransportType != TransportType.Amqp)
 299            {
 6300                connectionStringBuilder.Append(TransportTypeConfigName).Append(KeyValueSeparator).Append(this.TransportT
 301            }
 302
 34303            if (this.OperationTimeout != Constants.DefaultOperationTimeout)
 304            {
 2305                connectionStringBuilder.Append(OperationTimeoutConfigName).Append(KeyValueSeparator).Append(this.Operati
 306            }
 307
 34308            if (this.Authentication == AuthenticationType.ManagedIdentity)
 309            {
 6310                connectionStringBuilder.Append(AuthenticationConfigName).Append(KeyValueSeparator).Append("Managed Ident
 311            }
 312
 34313            return connectionStringBuilder.ToString().Trim(';');
 314        }
 315
 316        /// <summary>
 317        /// Returns an interoperable connection string that can be used to connect to the given ServiceBus Entity
 318        /// </summary>
 319        /// <returns>Entity connection string</returns>
 320        public string GetEntityConnectionString()
 321        {
 8322            if (string.IsNullOrWhiteSpace(this.EntityPath))
 323            {
 0324                throw Fx.Exception.ArgumentNullOrWhiteSpace(nameof(this.EntityPath));
 325            }
 326
 8327            return $"{this.GetNamespaceConnectionString()}{KeyValuePairDelimiter}{EntityPathConfigName}{KeyValueSeparato
 328        }
 329
 330        /// <summary>
 331        /// Returns an interoperable connection string that can be used to connect to ServiceBus Namespace
 332        /// </summary>
 333        /// <returns>The connection string</returns>
 334        public override string ToString()
 335        {
 16336            if (string.IsNullOrWhiteSpace(this.EntityPath))
 337            {
 8338                return this.GetNamespaceConnectionString();
 339            }
 340
 8341            return this.GetEntityConnectionString();
 342        }
 343
 344        void ParseConnectionString(string connectionString)
 345        {
 346            // First split based on ';'
 58347            var keyValuePairs = connectionString.Split(new[] { KeyValuePairDelimiter }, StringSplitOptions.RemoveEmptyEn
 414348            foreach (var keyValuePair in keyValuePairs)
 349            {
 350                // Now split based on the _first_ '='
 152351                var keyAndValue = keyValuePair.Split(new[] { KeyValueSeparator }, 2);
 152352                var key = keyAndValue[0];
 152353                if (keyAndValue.Length != 2)
 354                {
 0355                    throw Fx.Exception.Argument(nameof(connectionString), $"Value for the connection string parameter na
 356                }
 357
 152358                var value = keyAndValue[1].Trim();
 152359                if (key.Equals(EndpointConfigName, StringComparison.OrdinalIgnoreCase))
 360                {
 58361                    this.Endpoint = value;
 362                }
 94363                else if (key.Equals(SharedAccessKeyNameConfigName, StringComparison.OrdinalIgnoreCase))
 364                {
 28365                    this.SasKeyName = value;
 366                }
 66367                else if (key.Equals(EntityPathConfigName, StringComparison.OrdinalIgnoreCase))
 368                {
 2369                    this.EntityPath = value;
 370                }
 64371                else if (key.Equals(SharedAccessKeyConfigName, StringComparison.OrdinalIgnoreCase))
 372                {
 26373                    this.SasKey = value;
 374                }
 38375                else if (key.Equals(SharedAccessSignatureConfigName, StringComparison.OrdinalIgnoreCase))
 376                {
 4377                    this.SasToken = value;
 378                }
 34379                else if (key.Equals(TransportTypeConfigName, StringComparison.OrdinalIgnoreCase))
 380                {
 4381                    if (Enum.TryParse(value, true, out TransportType transportType))
 382                    {
 4383                        this.TransportType = transportType;
 384                    }
 385                }
 30386                else if (key.Equals(OperationTimeoutConfigName, StringComparison.OrdinalIgnoreCase))
 387                {
 6388                    if (int.TryParse(value, NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out var timeoutInSecon
 389                    {
 2390                        this.OperationTimeout = TimeSpan.FromSeconds(timeoutInSeconds);
 391                    }
 4392                    else if (TimeSpan.TryParse(value, NumberFormatInfo.InvariantInfo, out var operationTimeout))
 393                    {
 2394                        this.OperationTimeout = operationTimeout;
 395                    }
 396                    else
 397                    {
 2398                        throw Fx.Exception.Argument(nameof(connectionString), $"The {OperationTimeoutConfigName} ({value
 399                    }
 400
 4401                    if (this.OperationTimeout.TotalMilliseconds <= 0)
 402                    {
 0403                        throw Fx.Exception.Argument(nameof(connectionString), $"The {OperationTimeoutConfigName} ({value
 404                    }
 405
 4406                    if (this.OperationTimeout.TotalHours >= 1)
 407                    {
 0408                        throw Fx.Exception.Argument(nameof(connectionString), $"The {OperationTimeoutConfigName} ({value
 409                    }
 410                }
 24411                else if (key.Equals(AuthenticationConfigName, StringComparison.OrdinalIgnoreCase) && !int.TryParse(value
 412                {
 20413                    value = value.Replace(" ", string.Empty);
 20414                    if (!Enum.TryParse(value, true, out this.authType))
 415                    {
 4416                        this.authType = AuthenticationType.Other;
 417                    }
 418                }
 419                else
 420                {
 4421                    ConnectionStringProperties[key] = value;
 422                }
 423            }
 52424        }
 425    }
 426}