private static void SetEntityPath(ServiceBusConnectionStringProperties properties, string entityPath)
        {
            const BindingFlags internalScope = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetProperty;
            Type         propertiesType      = properties.GetType();
            PropertyInfo entityPathProperty  = propertiesType.GetProperty(nameof(properties.EntityPath));

            Guard.NotNull(entityPathProperty, nameof(entityPathProperty),
                          $"Requires a '{nameof(properties)}' property on the '{nameof(ServiceBusConnectionStringProperties)}' type");

            entityPathProperty?.SetValue(properties, entityPath, internalScope, binder: null, index: null, culture: null);
        }
        /// <summary>
        /// Gets the namespace-scoped Azure Service Bus connection string representation of the current set of <paramref name="properties"/>.
        /// </summary>
        /// <param name="properties">The Azure Service Bus property set of the separate connection string parts.</param>
        /// <exception cref="ArgumentNullException">
        ///     Thrown when the <paramref name="properties"/> is <c>null</c>
        ///     or doesn't contain the necessary properties or methods to determine the namespace-scoped connection string.
        /// </exception>
        public static string GetNamespaceConnectionString(this ServiceBusConnectionStringProperties properties)
        {
            Guard.NotNull(properties, nameof(properties), "Requires an Azure Service Bus properties instance to determine the namespace-scoped connection string");

            string originalEntityPath = properties.EntityPath;

            SetEntityPath(properties, entityPath: null);

            string connectionString = GetConnectionString(properties);

            SetEntityPath(properties, originalEntityPath);

            return(connectionString);
        }
        private static string GetConnectionString(ServiceBusConnectionStringProperties properties)
        {
            const BindingFlags internalScope = BindingFlags.NonPublic | BindingFlags.Instance;
            Type propertiesType = properties.GetType();

            const string connectionStringMethodName = "ToConnectionString";
            MethodInfo   connectionStringMethod     = propertiesType.GetMethod(connectionStringMethodName, internalScope);

            Guard.NotNull(connectionStringMethod, nameof(properties),
                          $"Requires a '{connectionStringMethodName}' method on the '{nameof(ServiceBusConnectionStringProperties)}'");

            var connectionString = connectionStringMethod?.Invoke(properties, new object[0]) as string;

            if (string.IsNullOrWhiteSpace(connectionStringMethodName))
            {
                throw new InvalidOperationException(
                          "Could not determine the Azure Service Bus namespace-scoped connection string from the given connection string properties");
            }

            return(connectionString);
        }
Exemple #4
0
        /// <summary>
        ///   Initializes a new instance of the <see cref="ServiceBusConnection"/> class.
        /// </summary>
        ///
        /// <param name="connectionString">The connection string to use for connecting to the Service Bus namespace.</param>
        /// <param name="options">A set of options to apply when configuring the connection.</param>
        ///
        /// <remarks>
        ///   If the connection string is copied from the Service Bus entity itself, it will contain the name of the desired Service Bus entity,
        ///   and can be used directly without passing the  name="entityName" />.  The name of the Service Bus entity should be
        ///   passed only once, either as part of the connection string or separately.
        /// </remarks>
        ///
        internal ServiceBusConnection(
            string connectionString,
            ServiceBusClientOptions options)
        {
            Argument.AssertNotNullOrEmpty(connectionString, nameof(connectionString));
            ValidateConnectionOptions(options);

            var connectionStringProperties = ServiceBusConnectionStringProperties.Parse(connectionString);

            ValidateConnectionStringProperties(connectionStringProperties, nameof(connectionString));

            FullyQualifiedNamespace = connectionStringProperties.Endpoint.Host;
            TransportType           = options.TransportType;
            EntityPath   = connectionStringProperties.EntityPath;
            RetryOptions = options.RetryOptions;

            SharedAccessSignature sharedAccessSignature;

            if (string.IsNullOrEmpty(connectionStringProperties.SharedAccessSignature))
            {
                sharedAccessSignature = new SharedAccessSignature(
                    BuildConnectionResource(options.TransportType, FullyQualifiedNamespace, EntityPath),
                    connectionStringProperties.SharedAccessKeyName,
                    connectionStringProperties.SharedAccessKey);
            }
            else
            {
                sharedAccessSignature = new SharedAccessSignature(connectionStringProperties.SharedAccessSignature);
            }

            var sharedCredential = new SharedAccessSignatureCredential(sharedAccessSignature);
            var tokenCredential  = new ServiceBusTokenCredential(
                sharedCredential,
                BuildConnectionResource(TransportType, FullyQualifiedNamespace, EntityPath));

#pragma warning disable CA2214 // Do not call overridable methods in constructors. This internal method is virtual for testing purposes.
            _innerClient = CreateTransportClient(tokenCredential, options);
#pragma warning restore CA2214 // Do not call overridable methods in constructors
        }
Exemple #5
0
        /// <summary>
        ///   Performs the actions needed to validate the set of connection string properties for connecting to the
        ///   Service Bus service.
        /// </summary>
        ///
        /// <param name="connectionStringProperties">The set of connection string properties to validate.</param>
        /// <param name="connectionStringArgumentName">The name of the argument associated with the connection string; to be used when raising <see cref="ArgumentException" /> variants.</param>
        ///
        /// <exception cref="ArgumentException">In the case that the properties violate an invariant or otherwise represent a combination that is not permissible, an appropriate exception will be thrown.</exception>
        ///
        private static void ValidateConnectionStringProperties(
            ServiceBusConnectionStringProperties connectionStringProperties,
            string connectionStringArgumentName)
        {
            var hasSharedKey       = ((!string.IsNullOrEmpty(connectionStringProperties.SharedAccessKeyName)) && (!string.IsNullOrEmpty(connectionStringProperties.SharedAccessKey)));
            var hasSharedSignature = (!string.IsNullOrEmpty(connectionStringProperties.SharedAccessSignature));

            // Ensure that each of the needed components are present for connecting.

            if ((string.IsNullOrEmpty(connectionStringProperties.Endpoint?.Host)) ||
                ((!hasSharedKey) && (!hasSharedSignature)))
            {
                throw new ArgumentException(Resources.MissingConnectionInformation, connectionStringArgumentName);
            }

            // The connection string may contain a precomputed shared access signature OR a shared key name and value,
            // but not both.

            if (hasSharedKey && hasSharedSignature)
            {
                throw new ArgumentException(Resources.OnlyOneSharedAccessAuthorizationMayBeSpecified, connectionStringArgumentName);
            }
        }
Exemple #6
0
        /// <summary>
        ///   Parses the specified Service Bus connection string into its component properties.
        /// </summary>
        ///
        /// <param name="connectionString">The connection string to parse.</param>
        ///
        /// <returns>The component properties parsed from the connection string.</returns>
        ///
        /// <exception cref="FormatException">The specified connection string was malformed and could not be parsed.</exception>
        ///
        public static ServiceBusConnectionStringProperties Parse(string connectionString)
        {
            Argument.AssertNotNullOrEmpty(connectionString, nameof(connectionString));

            var parsedValues          = new ServiceBusConnectionStringProperties();
            var tokenPositionModifier = (connectionString[0] == TokenValuePairDelimiter) ? 0 : 1;
            var lastPosition          = 0;
            var currentPosition       = 0;

            int    valueStart;
            string slice;
            string token;
            string value;

            while (currentPosition != -1)
            {
                // Slice the string into the next token/value pair.

                currentPosition = connectionString.IndexOf(TokenValuePairDelimiter, lastPosition + 1);

                if (currentPosition >= 0)
                {
                    slice = connectionString.Substring(lastPosition, (currentPosition - lastPosition));
                }
                else
                {
                    slice = connectionString.Substring(lastPosition);
                }

                // Break the token and value apart, if this is a legal pair.

                valueStart = slice.IndexOf(TokenValueSeparator);

                if (valueStart >= 0)
                {
                    token = slice.Substring((1 - tokenPositionModifier), (valueStart - 1 + tokenPositionModifier));
                    value = slice.Substring(valueStart + 1);

                    // Guard against leading and trailing spaces, only trimming if there is a need.

                    if ((!string.IsNullOrEmpty(token)) && (char.IsWhiteSpace(token[0])) || char.IsWhiteSpace(token[token.Length - 1]))
                    {
                        token = token.Trim();
                    }

                    if ((!string.IsNullOrEmpty(value)) && (char.IsWhiteSpace(value[0]) || char.IsWhiteSpace(value[value.Length - 1])))
                    {
                        value = value.Trim();
                    }

                    // If there was no value for a key, then consider the connection string to
                    // be malformed.

                    if (string.IsNullOrEmpty(value))
                    {
                        throw new FormatException(Resources.InvalidConnectionString);
                    }

                    // Compare the token against the known connection string properties and capture the
                    // pair if they are a known attribute.

                    if (string.Compare(EndpointToken, token, StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        var endpointBuilder = new UriBuilder(value)
                        {
                            Scheme = ServiceBusEndpointScheme,
                            Port   = -1
                        };

                        if ((string.Compare(endpointBuilder.Scheme, ServiceBusEndpointSchemeName, StringComparison.OrdinalIgnoreCase) != 0) ||
                            (Uri.CheckHostName(endpointBuilder.Host) == UriHostNameType.Unknown))
                        {
                            throw new FormatException(Resources.InvalidConnectionString);
                        }

                        parsedValues.Endpoint = endpointBuilder.Uri;
                    }
                    else if (string.Compare(EntityPathToken, token, StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        parsedValues.EntityPath = value;
                    }
                    else if (string.Compare(SharedAccessKeyNameToken, token, StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        parsedValues.SharedAccessKeyName = value;
                    }
                    else if (string.Compare(SharedAccessKeyValueToken, token, StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        parsedValues.SharedAccessKey = value;
                    }
                    else if (string.Compare(SharedAccessSignatureToken, token, StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        parsedValues.SharedAccessSignature = value;
                    }
                }
                else if ((slice.Length != 1) || (slice[0] != TokenValuePairDelimiter))
                {
                    // This wasn't a legal pair and it is not simply a trailing delimiter; consider
                    // the connection string to be malformed.

                    throw new FormatException(Resources.InvalidConnectionString);
                }

                tokenPositionModifier = 0;
                lastPosition          = currentPosition;
            }

            return(parsedValues);
        }