Example #1
0
        /// <summary>
        ///   Initializes a new instance of the <see cref="EventHubConnection"/> class.
        /// </summary>
        ///
        /// <param name="fullyQualifiedNamespace">The fully qualified Event Hubs namespace to connect to.  This is likely to be similar to <c>{yournamespace}.servicebus.windows.net</c>.</param>
        /// <param name="eventHubName">The name of the specific Event Hub to associate the connection with.</param>
        /// <param name="credential">The Azure managed identity credential to use for authorization.  Access controls may be specified by the Event Hubs namespace or the requested Event Hub, depending on Azure configuration.</param>
        /// <param name="connectionOptions">A set of options to apply when configuring the connection.</param>
        ///
        public EventHubConnection(string fullyQualifiedNamespace,
                                  string eventHubName,
                                  TokenCredential credential,
                                  EventHubConnectionOptions connectionOptions = default)
        {
            Argument.AssertWellFormedEventHubsNamespace(fullyQualifiedNamespace, nameof(fullyQualifiedNamespace));
            Argument.AssertNotNullOrEmpty(eventHubName, nameof(eventHubName));
            Argument.AssertNotNull(credential, nameof(credential));

            connectionOptions = connectionOptions?.Clone() ?? new EventHubConnectionOptions();
            ValidateConnectionOptions(connectionOptions);

            var tokenCredential = new EventHubTokenCredential(credential);

            FullyQualifiedNamespace = fullyQualifiedNamespace;
            EventHubName            = eventHubName;
            Options = connectionOptions;

#pragma warning disable CA2214 // Do not call overridable methods in constructors. This internal method is virtual for testing purposes.
            InnerClient = CreateTransportClient(fullyQualifiedNamespace, eventHubName, tokenCredential, connectionOptions);
#pragma warning restore CA2214 // Do not call overridable methods in constructors.
        }
Example #2
0
        /// <summary>
        ///   Initializes a new instance of the <see cref="EventHubConnection"/> class.
        /// </summary>
        ///
        /// <param name="connectionString">The connection string to use for connecting to the Event Hubs namespace; it is expected that the shared key properties are contained in this connection string, but not the Event Hub name.</param>
        /// <param name="eventHubName">The name of the specific Event Hub to associate the connection with.</param>
        /// <param name="connectionOptions">A set of options to apply when configuring the connection.</param>
        ///
        /// <remarks>
        ///   If the connection string is copied from the Event Hub itself, it will contain the name of the desired Event Hub,
        ///   and can be used directly without passing the <paramref name="eventHubName" />.  The name of the Event Hub should be
        ///   passed only once, either as part of the connection string or separately.
        /// </remarks>
        ///
        public EventHubConnection(string connectionString,
                                  string eventHubName,
                                  EventHubConnectionOptions connectionOptions)
        {
            Argument.AssertNotNullOrEmpty(connectionString, nameof(connectionString));

            connectionOptions = connectionOptions?.Clone() ?? new EventHubConnectionOptions();
            ValidateConnectionOptions(connectionOptions);

            ConnectionStringProperties connectionStringProperties = ConnectionStringParser.Parse(connectionString);

            ValidateConnectionProperties(connectionStringProperties, eventHubName, nameof(connectionString));

            var fullyQualifiedNamespace = connectionStringProperties.Endpoint.Host;

            if (string.IsNullOrEmpty(eventHubName))
            {
                eventHubName = connectionStringProperties.EventHubName;
            }

            var sharedAccessSignature = new SharedAccessSignature
                                        (
                BuildAudienceResource(connectionOptions.TransportType, fullyQualifiedNamespace, eventHubName),
                connectionStringProperties.SharedAccessKeyName,
                connectionStringProperties.SharedAccessKey
                                        );

            var sharedCredentials = new SharedAccessSignatureCredential(sharedAccessSignature);
            var tokenCredentials  = new EventHubTokenCredential(sharedCredentials, BuildAudienceResource(connectionOptions.TransportType, fullyQualifiedNamespace, eventHubName));

            FullyQualifiedNamespace = fullyQualifiedNamespace;
            EventHubName            = eventHubName;
            Options = connectionOptions;

#pragma warning disable CA2214 // Do not call overridable methods in constructors. This internal method is virtual for testing purposes.
            InnerClient = CreateTransportClient(fullyQualifiedNamespace, eventHubName, tokenCredentials, connectionOptions);
#pragma warning restore CA2214 // Do not call overridable methods in constructors.
        }
        /// <summary>
        ///   Initializes a new instance of the <see cref="AmqpConnectionScope"/> class.
        /// </summary>
        ///
        /// <param name="serviceEndpoint">Endpoint for the Event Hubs service to which the scope is associated.</param>
        /// <param name="eventHubName"> The name of the Event Hub to which the scope is associated</param>
        /// <param name="credential">The credential to use for authorization with the Event Hubs 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,
                                   string eventHubName,
                                   EventHubTokenCredential credential,
                                   EventHubsTransportType transport,
                                   IWebProxy proxy,
                                   string identifier = default)
        {
            Argument.AssertNotNull(serviceEndpoint, nameof(serviceEndpoint));
            Argument.AssertNotNullOrEmpty(eventHubName, nameof(eventHubName));
            Argument.AssertNotNull(credential, nameof(credential));
            ValidateTransport(transport);

            ServiceEndpoint = serviceEndpoint;
            EventHubName    = eventHubName;
            Transport       = transport;
            Proxy           = proxy;
            TokenProvider   = new CbsTokenProvider(new EventHubTokenCredential(credential, serviceEndpoint.ToString()), OperationCancellationSource.Token);
            Id = identifier ?? $"{ eventHubName }-{ 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);
        }
        /// <summary>
        ///   Initializes a new instance of the <see cref="CbsTokenProvider"/> class.
        /// </summary>
        ///
        /// <param name="credential">The credential to use for access token generation.</param>
        /// <param name="tokenExpirationBuffer">The amount of time to buffer expiration</param>
        /// <param name="cancellationToken">The cancellation token to consider when making requests.</param>
        ///
        public CbsTokenProvider(EventHubTokenCredential credential,
                                TimeSpan tokenExpirationBuffer,
                                CancellationToken cancellationToken)
        {
            Argument.AssertNotNull(credential, nameof(credential));
            Argument.AssertNotNegative(tokenExpirationBuffer, nameof(tokenExpirationBuffer));

            Credential            = credential;
            TokenExpirationBuffer = tokenExpirationBuffer;
            CancellationToken     = cancellationToken;

            TokenType = (credential.IsSharedAccessCredential)
                ? SharedAccessTokenType
                : JsonWebTokenType;

            // Tokens are only cached for JWT-based credentials; no need
            // to instantiate the semaphore if no caching is taking place.

            if (!credential.IsSharedAccessCredential)
            {
                TokenAcquireGuard = new SemaphoreSlim(1, 1);
            }
        }
Example #5
0
        /// <summary>
        ///   Initializes a new instance of the <see cref="AmqpClient"/> class.
        /// </summary>
        ///
        /// <param name="host">The fully qualified host name for the Event Hubs namespace.  This is likely to be similar to <c>{yournamespace}.servicebus.windows.net</c>.</param>
        /// <param name="eventHubName">The name of the specific Event Hub to connect the client to.</param>
        /// <param name="operationTimeout">The amount of time to allow for an AMQP operation using the link to complete before attempting to cancel it.</param>
        /// <param name="credential">The Azure managed identity credential to use for authorization.  Access controls may be specified by the Event Hubs namespace or the requested Event Hub, depending on Azure configuration.</param>
        /// <param name="clientOptions">A set of options to apply when configuring the client.</param>
        /// <param name="connectionScope">The optional scope to use for AMQP connection management.  If <c>null</c>, a new scope will be created.</param>
        /// <param name="messageConverter">The optional converter to use for transforming AMQP message-related types.  If <c>null</c>, a new converter will be created.</param>
        ///
        /// <remarks>
        ///   As an internal type, this class performs only basic sanity checks against its arguments.  It
        ///   is assumed that callers are trusted and have performed deep validation.
        ///
        ///   Any parameters passed are assumed to be owned by this instance and safe to mutate or dispose;
        ///   creation of clones or otherwise protecting the parameters is assumed to be the purview of the
        ///   caller.
        /// </remarks>
        ///
        protected AmqpClient(string host,
                             string eventHubName,
                             TimeSpan operationTimeout,
                             EventHubTokenCredential credential,
                             EventHubConnectionOptions clientOptions,
                             AmqpConnectionScope connectionScope,
                             AmqpMessageConverter messageConverter)
        {
            Argument.AssertNotNullOrEmpty(host, nameof(host));
            Argument.AssertNotNullOrEmpty(eventHubName, nameof(eventHubName));
            Argument.AssertNotNegative(operationTimeout, nameof(operationTimeout));
            Argument.AssertNotNull(credential, nameof(credential));
            Argument.AssertNotNull(clientOptions, nameof(clientOptions));

            try
            {
                EventHubsEventSource.Log.EventHubClientCreateStart(host, eventHubName);

                ServiceEndpoint = new UriBuilder
                {
                    Scheme = clientOptions.TransportType.GetUriScheme(),
                    Host   = host
                }.Uri;

                ConnectionEndpoint = clientOptions.CustomEndpointAddress switch
                {
                    null => ServiceEndpoint,

                    _ => new UriBuilder
                    {
                        Scheme = ServiceEndpoint.Scheme,
                        Host   = clientOptions.CustomEndpointAddress.Host
                    }.Uri
                };

                EventHubName     = eventHubName;
                Credential       = credential;
                MessageConverter = messageConverter ?? new AmqpMessageConverter();

                ConnectionScope = connectionScope ?? new AmqpConnectionScope(
                    ServiceEndpoint,
                    ConnectionEndpoint,
                    eventHubName,
                    credential,
                    clientOptions.TransportType,
                    clientOptions.Proxy,
                    clientOptions.ConnectionIdleTimeout,
                    null,
                    clientOptions.SendBufferSizeInBytes,
                    clientOptions.ReceiveBufferSizeInBytes,
                    clientOptions.CertificateValidationCallback);

                ManagementLink = new FaultTolerantAmqpObject <RequestResponseAmqpLink>(
                    linkTimeout => ConnectionScope.OpenManagementLinkAsync(operationTimeout, linkTimeout, CancellationToken.None),
                    link =>
                {
                    link.Session?.SafeClose();
                    link.SafeClose();
                    EventHubsEventSource.Log.FaultTolerantAmqpObjectClose(nameof(RequestResponseAmqpLink), "", EventHubName, "", "", link.TerminalException?.Message);
                });
            }
            finally
            {
                EventHubsEventSource.Log.EventHubClientCreateComplete(host, eventHubName);
            }
        }
Example #6
0
 internal override TransportClient CreateTransportClient(string fullyQualifiedNamespace,
                                                         string eventHubName,
                                                         EventHubTokenCredential credential,
                                                         EventHubConnectionOptions options) => Mock.Of <TransportClient>();
 /// <summary>
 ///   Initializes a new instance of the <see cref="AmqpClient"/> class.
 /// </summary>
 ///
 /// <param name="host">The fully qualified host name for the Event Hubs namespace.  This is likely to be similar to <c>{yournamespace}.servicebus.windows.net</c>.</param>
 /// <param name="eventHubName">The name of the specific Event Hub to connect the client to.</param>
 /// <param name="credential">The Azure managed identity credential to use for authorization.  Access controls may be specified by the Event Hubs namespace or the requested Event Hub, depending on Azure configuration.</param>
 /// <param name="clientOptions">A set of options to apply when configuring the client.</param>
 ///
 /// <remarks>
 ///   As an internal type, this class performs only basic sanity checks against its arguments.  It
 ///   is assumed that callers are trusted and have performed deep validation.
 ///
 ///   Any parameters passed are assumed to be owned by this instance and safe to mutate or dispose;
 ///   creation of clones or otherwise protecting the parameters is assumed to be the purview of the
 ///   caller.
 /// </remarks>
 ///
 public AmqpClient(string host,
                   string eventHubName,
                   EventHubTokenCredential credential,
                   EventHubConnectionOptions clientOptions) : this(host, eventHubName, credential, clientOptions, null, null)
 {
 }
Example #8
0
            internal override TransportClient CreateTransportClient(string fullyQualifiedNamespace, string eventHubName, EventHubTokenCredential credential, EventHubConnectionOptions options)
            {
                var client = new Mock <TransportClient>();

                client
                .Setup(client => client.ServiceEndpoint)
                .Returns(new Uri($"amgp://{ fullyQualifiedNamespace }.com/{ eventHubName }"));

                return(client.Object);
            }
Example #9
0
 internal override TransportClient CreateTransportClient(string fullyQualifiedNamespace, string eventHubName, EventHubTokenCredential credential, EventHubConnectionOptions options)
 {
     TransportClientOptions = options;
     _transportClient       = new ObservableTransportClientMock();
     return(_transportClient);
 }