/// <summary>
        ///   Initializes a new instance of the <see cref="AmqpConnectionScope"/> class.
        /// </summary>
        ///
        /// <param name="serviceEndpoint">Endpoint for the Service Bus service to which the scope is associated.</param>
        /// <param name="credential">The credential to use for authorization with the Service Bus service.</param>
        /// <param name="transport">The transport to use for communication.</param>
        /// <param name="proxy">The proxy, if any, to use for communication.</param>
        /// <param name="identifier">The identifier to assign this scope; if not provided, one will be generated.</param>
        ///
        public AmqpConnectionScope(Uri serviceEndpoint,
                                   ServiceBusTokenCredential credential,
                                   ServiceBusTransportType transport,
                                   IWebProxy proxy,
                                   string identifier = default)
        {
            Argument.AssertNotNull(serviceEndpoint, nameof(serviceEndpoint));
            Argument.AssertNotNull(credential, nameof(credential));
            ValidateTransport(transport);

            ServiceEndpoint = serviceEndpoint;
            Transport       = transport;
            Proxy           = proxy;
            TokenProvider   = new CbsTokenProvider(new ServiceBusTokenCredential(credential, serviceEndpoint.ToString()), OperationCancellationSource.Token);
            Id = identifier ?? $"{ ServiceEndpoint }-{ Guid.NewGuid().ToString("D").Substring(0, 8) }";

            Task <AmqpConnection> connectionFactory(TimeSpan timeout) => CreateAndOpenConnectionAsync(AmqpVersion, ServiceEndpoint, Transport, Proxy, Id, timeout);

            ActiveConnection = new FaultTolerantAmqpObject <AmqpConnection>(
                connectionFactory,
                CloseConnection);
            TransactionController = new FaultTolerantAmqpObject <Controller>(
                CreateControllerAsync,
                CloseController);
        }
        /// <summary>
        ///   Initializes a new instance of the <see cref="AmqpConnectionScope"/> class.
        /// </summary>
        ///
        /// <param name="serviceEndpoint">Endpoint for the Service Bus service to which the scope is associated.</param>
        /// <param name="credential">The credential to use for authorization with the Service Bus service.</param>
        /// <param name="transport">The transport to use for communication.</param>
        /// <param name="proxy">The proxy, if any, to use for communication.</param>
        /// <param name="identifier">The identifier to assign this scope; if not provided, one will be generated.</param>
        ///
        public AmqpConnectionScope(Uri serviceEndpoint,
                                   ServiceBusTokenCredential credential,
                                   ServiceBusTransportType transport,
                                   IWebProxy proxy,
                                   string identifier = default)
        {
            Argument.AssertNotNull(serviceEndpoint, nameof(serviceEndpoint));
            Argument.AssertNotNull(credential, nameof(credential));
            ValidateTransport(transport);

            ServiceEndpoint = serviceEndpoint;
            Transport       = transport;
            Proxy           = proxy;
            TokenProvider   = new CbsTokenProvider(new ServiceBusTokenCredential(credential, serviceEndpoint.ToString()), OperationCancellationSource.Token);
            Id = identifier ?? $"{ ServiceEndpoint }-{ Guid.NewGuid().ToString("D", CultureInfo.InvariantCulture).Substring(0, 8) }";

#pragma warning disable CA2214 // Do not call overridable methods in constructors. This internal method is virtual for testing purposes.
            Task <AmqpConnection> connectionFactory(TimeSpan timeout) => CreateAndOpenConnectionAsync(AmqpVersion, ServiceEndpoint, Transport, Proxy, Id, timeout);

#pragma warning restore CA2214 // Do not call overridable methods in constructors
            ActiveConnection = new FaultTolerantAmqpObject <AmqpConnection>(
                connectionFactory,
                CloseConnection);
            TransactionController = new FaultTolerantAmqpObject <Controller>(
                CreateControllerAsync,
                CloseController);
        }
        /// <summary>
        ///   Builds the audience of the connection for use in the signature.
        /// </summary>
        ///
        /// <param name="transportType">The type of protocol and transport that will be used for communicating with the Service Bus service.</param>
        /// <param name="fullyQualifiedNamespace">The fully qualified Service Bus namespace.  This is likely to be similar to <c>{yournamespace}.servicebus.windows.net</c>.</param>
        /// <param name="entityName">The name of the specific entity to connect the client to.</param>
        ///
        /// <returns>The value to use as the audience of the signature.</returns>
        ///
        internal static string BuildConnectionResource(
            ServiceBusTransportType transportType,
            string fullyQualifiedNamespace,
            string entityName)
        {
            // If there is no namespace, there is no basis for a URL and the
            // resource is empty.

            if (string.IsNullOrEmpty(fullyQualifiedNamespace))
            {
                return(string.Empty);
            }

            var builder = new UriBuilder(fullyQualifiedNamespace)
            {
                Scheme   = transportType.GetUriScheme(),
                Path     = entityName,
                Port     = -1,
                Fragment = string.Empty,
                Password = string.Empty,
                UserName = string.Empty,
            };

            if (builder.Path.EndsWith("/", StringComparison.Ordinal))
            {
                builder.Path = builder.Path.TrimEnd('/');
            }

            return(builder.Uri.AbsoluteUri.ToLowerInvariant());
        }
Example #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));
            Argument.AssertNotNull(options, nameof(options));

            options = options.Clone();

            ValidateConnectionOptions(options);
            var builder = new ServiceBusConnectionStringBuilder(connectionString);

            FullyQualifiedNamespace = builder.FullyQualifiedNamespace;
            TransportType           = options.TransportType;
            EntityPath = builder.EntityName;
            var sharedAccessSignature = new SharedAccessSignature
                                        (
                BuildAudienceResource(options.TransportType, FullyQualifiedNamespace, EntityPath),
                builder.SasKeyName,
                builder.SasKey
                                        );

            var sharedCredentials = new SharedAccessSignatureCredential(sharedAccessSignature);
            var tokenCredentials  = new ServiceBusTokenCredential(
                sharedCredentials,
                BuildAudienceResource(options.TransportType, FullyQualifiedNamespace, EntityPath));

            _innerClient = CreateTransportClient(tokenCredentials, options);
        }
Example #5
0
        /// <summary>
        ///   Initializes a new instance of the <see cref="ServiceBusConnection"/> class.
        /// </summary>
        ///
        /// <param name="fullyQualifiedNamespace">The fully qualified Service Bus namespace to connect to.  This is likely to be similar to <c>{yournamespace}.servicebus.windows.net</c>.</param>
        /// <param name="credential">The Azure managed identity credential to use for authorization.  Access controls may be specified by the Service Bus namespace or the requested Service Bus entity, depending on Azure configuration.</param>
        /// <param name="options">A set of options to apply when configuring the connection.</param>
        ///
        internal ServiceBusConnection(
            string fullyQualifiedNamespace,
            TokenCredential credential,
            ServiceBusClientOptions options)
        {
            Argument.AssertNotNullOrEmpty(fullyQualifiedNamespace, nameof(fullyQualifiedNamespace));
            Argument.AssertNotNull(credential, nameof(credential));
            Argument.AssertNotNull(options, nameof(options));

            options = options.Clone();
            ValidateConnectionOptions(options);
            switch (credential)
            {
            case SharedAccessSignatureCredential _:
                break;

            case ServiceBusSharedKeyCredential sharedKeyCredential:
                credential = sharedKeyCredential.AsSharedAccessSignatureCredential(BuildAudienceResource(options.TransportType, fullyQualifiedNamespace, EntityPath));
                break;
            }

            var tokenCredential = new ServiceBusTokenCredential(credential, BuildAudienceResource(options.TransportType, fullyQualifiedNamespace, EntityPath));

            FullyQualifiedNamespace = fullyQualifiedNamespace;
            TransportType           = options.TransportType;

            _innerClient = CreateTransportClient(tokenCredential, options);
        }
Example #6
0
 public MockConnectionMockScope(
     Uri serviceEndpoint,
     ServiceBusTokenCredential credential,
     ServiceBusTransportType transport,
     IWebProxy proxy) : base(serviceEndpoint, credential, transport, proxy)
 {
     MockConnection = new Mock <AmqpConnection>(new MockTransport(), CreateMockAmqpSettings(), new AmqpConnectionSettings());
 }
        /// <summary>
        ///   Translates an <see cref="ServiceBusSharedAccessKeyCredential"/> into the equivalent shared access signature credential.
        /// </summary>
        ///
        /// <param name="credential">The credential to translate.</param>
        /// <param name="fullyQualifiedNamespace">The fully qualified Service Bus namespace being connected to.</param>
        /// <param name="entityPath">The path of the entity being connected to.</param>
        /// <param name="transportType">The type of transport being used for the connection.</param>
        ///
        /// <returns>The <see cref="SharedAccessSignatureCredential" /> which the <paramref name="credential" /> was translated into.</returns>
        ///
        internal static SharedAccessSignatureCredential TranslateSharedKeyCredential(ServiceBusSharedAccessKeyCredential credential,
                                                                                     string fullyQualifiedNamespace,
                                                                                     string entityPath,
                                                                                     ServiceBusTransportType transportType)
        {
            if ((credential == null) || (string.IsNullOrEmpty(fullyQualifiedNamespace)))
            {
                return(null);
            }

            return(credential.AsSharedAccessSignatureCredential(BuildConnectionResource(transportType, fullyQualifiedNamespace, entityPath)));
        }
        /// <summary>
        ///   Determines the URI scheme to be used for the given connection type.
        /// </summary>
        ///
        /// <param name="instance">The instance that this method was invoked on.</param>
        ///
        /// <returns>The scheme that should be used for the given connection type when forming an associated URI.</returns>
        ///
        public static string GetUriScheme(this ServiceBusTransportType instance)
        {
            switch (instance)
            {
            case ServiceBusTransportType.AmqpTcp:
            case ServiceBusTransportType.AmqpWebSockets:
                return(AmqpUriScheme);

            default:
                throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.InvalidTransportType, instance.ToString(), nameof(instance)));
            }
        }
        /// <summary>
        ///   Creates an AMQP connection for a given scope.
        /// </summary>
        ///
        /// <param name="amqpVersion">The version of AMQP to use for the connection.</param>
        /// <param name="serviceEndpoint">The endpoint for the Service Bus service to which the scope is associated.</param>
        /// <param name="transportType">The type of transport to use for communication.</param>
        /// <param name="proxy">The proxy, if any, to use for communication.</param>
        /// <param name="scopeIdentifier">The unique identifier for the associated scope.</param>
        /// <param name="timeout">The timeout to consider when creating the connection.</param>
        ///
        /// <returns>An AMQP connection that may be used for communicating with the Service Bus service.</returns>
        ///
        protected virtual async Task <AmqpConnection> CreateAndOpenConnectionAsync(
            Version amqpVersion,
            Uri serviceEndpoint,
            ServiceBusTransportType transportType,
            IWebProxy proxy,
            string scopeIdentifier,
            TimeSpan timeout)
        {
            var                    hostName          = serviceEndpoint.Host;
            AmqpSettings           amqpSettings      = CreateAmpqSettings(AmqpVersion);
            AmqpConnectionSettings connectionSetings = CreateAmqpConnectionSettings(hostName, scopeIdentifier);

            TransportSettings transportSettings = transportType.IsWebSocketTransport()
                ? CreateTransportSettingsForWebSockets(hostName, proxy)
                : CreateTransportSettingsforTcp(hostName, serviceEndpoint.Port);

            // Create and open the connection, respecting the timeout constraint
            // that was received.

            var stopWatch = Stopwatch.StartNew();

            var           initiator = new AmqpTransportInitiator(amqpSettings, transportSettings);
            TransportBase transport = await initiator.ConnectTaskAsync(timeout).ConfigureAwait(false);

            var connection = new AmqpConnection(transport, amqpSettings, connectionSetings);

            await OpenAmqpObjectAsync(connection, timeout.CalculateRemaining(stopWatch.Elapsed)).ConfigureAwait(false);

            stopWatch.Stop();

            // Create the CBS link that will be used for authorization.  The act of creating the link will associate
            // it with the connection.

            new AmqpCbsLink(connection);

            // When the connection is closed, close each of the links associated with it.

            EventHandler closeHandler = null;

            closeHandler = (snd, args) =>
            {
                foreach (var link in ActiveLinks.Keys)
                {
                    link.SafeClose();
                }

                connection.Closed -= closeHandler;
            };

            connection.Closed += closeHandler;
            return(connection);
        }
Example #10
0
 internal static string ToSerializedValue(this ServiceBusTransportType value)
 {
     switch( value )
     {
         case ServiceBusTransportType.NotSpecified:
             return "NotSpecified";
         case ServiceBusTransportType.NetMessaging:
             return "NetMessaging";
         case ServiceBusTransportType.AMQP:
             return "AMQP";
     }
     return null;
 }
        /// <summary>
        ///   Builds the audience for use in the signature.
        /// </summary>
        ///
        /// <param name="transportType">The type of protocol and transport that will be used for communicating with the Service Bus service.</param>
        /// <param name="fullyQualifiedNamespace">The fully qualified Service Bus namespace.  This is likely to be similar to <c>{yournamespace}.servicebus.windows.net</c>.</param>
        /// <param name="entityName">The name of the specific entity to connect the client to.</param>
        ///
        /// <returns>The value to use as the audience of the signature.</returns>
        ///
        private static string BuildAudienceResource(ServiceBusTransportType transportType,
                                                    string fullyQualifiedNamespace,
                                                    string entityName)
        {
            var builder = new UriBuilder(fullyQualifiedNamespace)
            {
                Scheme   = transportType.GetUriScheme(),
                Path     = entityName,
                Port     = -1,
                Fragment = string.Empty,
                Password = string.Empty,
                UserName = string.Empty,
            };

            if (builder.Path.EndsWith("/"))
            {
                builder.Path = builder.Path.TrimEnd('/');
            }

            return(builder.Uri.AbsoluteUri.ToLowerInvariant());
        }
Example #12
0
 /// <summary>
 /// Instantiates a new <see cref="ServiceBusConnectionStringBuilder"/>.
 /// </summary>
 /// <example>
 /// <code>
 /// var connectionStringBuilder = new ServiceBusConnectionStringBuilder(
 ///     "contoso.servicebus.windows.net",
 ///     "myQueue",
 ///     "{ ... SAS token ... }",
 ///     TransportType.Amqp
 /// );
 /// </code>
 /// </example>
 /// <param name="endpoint">Fully qualified endpoint.</param>
 /// <param name="entityPath"></param>
 /// <param name="sharedAccessSignature"></param>
 /// <param name="transportType"></param>
 public ServiceBusConnectionStringBuilder(string endpoint, string entityPath, string sharedAccessSignature, ServiceBusTransportType transportType)
     : this(endpoint, entityPath, sharedAccessSignature)
 {
     this.TransportType = transportType;
 }
Example #13
0
 private static ITransport GetTransportByType(ServiceBusTransportType transportType)
 {
     return _transportMap[transportType];
 }
 /// <summary>
 ///   Determines whether the specified transport makes use of web sockets.
 /// </summary>
 ///
 /// <param name="instance">The instance that this method was invoked on.</param>
 ///
 /// <returns><c>true</c> if the transport uses web sockets; otherwise, <c>false</c>.</returns>
 ///
 public static bool IsWebSocketTransport(this ServiceBusTransportType instance) => (instance == ServiceBusTransportType.AmqpWebSockets);