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); }
/// <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 }
/// <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); } }
/// <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); }