// This call is executed over AMQP.
        public override async Task SendAsync(string deviceId, string moduleId, Message message)
        {
            Logging.Enter(this, $"Sending message with Id [{message?.MessageId}] for device {deviceId}, module {moduleId}", nameof(SendAsync));

            if (string.IsNullOrWhiteSpace(deviceId))
            {
                throw new ArgumentNullException(nameof(deviceId));
            }

            if (string.IsNullOrWhiteSpace(moduleId))
            {
                throw new ArgumentNullException(nameof(moduleId));
            }

            if (message == null)
            {
                throw new ArgumentNullException(nameof(message));
            }

            if (_clientOptions?.SdkAssignsMessageId == SdkAssignsMessageId.WhenUnset && message.MessageId == null)
            {
                message.MessageId = Guid.NewGuid().ToString();
            }

            if (message.IsBodyCalled)
            {
                message.ResetBody();
            }

            using AmqpMessage amqpMessage = MessageConverter.MessageToAmqpMessage(message);
            amqpMessage.Properties.To     = "/devices/" + WebUtility.UrlEncode(deviceId) + "/modules/" + WebUtility.UrlEncode(moduleId) + "/messages/deviceBound";
            try
            {
                SendingAmqpLink sendingLink = await GetSendingLinkAsync().ConfigureAwait(false);

                Outcome outcome = await sendingLink
                                  .SendMessageAsync(
                    amqpMessage,
                    IotHubConnection.GetNextDeliveryTag(ref _sendingDeliveryTag),
                    AmqpConstants.NullBinary,
                    OperationTimeout)
                                  .ConfigureAwait(false);

                Logging.Info(this, $"Outcome was: {outcome?.DescriptorName}", nameof(SendAsync));

                if (outcome.DescriptorCode != Accepted.Code)
                {
                    throw AmqpErrorMapper.GetExceptionFromOutcome(outcome);
                }
            }
            catch (Exception ex) when(!ex.IsFatal())
            {
                Logging.Error(this, $"{nameof(SendAsync)} threw an exception: {ex}", nameof(SendAsync));
                throw AmqpClientHelper.ToIotHubClientContract(ex);
            }
            finally
            {
                Logging.Exit(this, $"Sending message with Id [{message?.MessageId}] for device {deviceId}, module {moduleId}", nameof(SendAsync));
            }
        }
        public async override Task SendAsync(string deviceId, Message message, TimeSpan?timeout = null)
        {
            if (string.IsNullOrWhiteSpace(deviceId))
            {
                throw new ArgumentNullException(nameof(deviceId));
            }

            if (message == null)
            {
                throw new ArgumentNullException(nameof(message));
            }
            timeout ??= OperationTimeout;

            using AmqpMessage amqpMessage = message.ToAmqpMessage();
            amqpMessage.Properties.To     = "/devices/" + WebUtility.UrlEncode(deviceId) + "/messages/deviceBound";

            try
            {
                SendingAmqpLink sendingLink = await GetSendingLinkAsync().ConfigureAwait(false);

                Outcome outcome = await sendingLink
                                  .SendMessageAsync(amqpMessage, IotHubConnection.GetNextDeliveryTag(ref _sendingDeliveryTag), AmqpConstants.NullBinary, timeout.Value)
                                  .ConfigureAwait(false);

                if (outcome.DescriptorCode != Accepted.Code)
                {
                    throw AmqpErrorMapper.GetExceptionFromOutcome(outcome);
                }
            }
            catch (Exception ex) when(!(ex is TimeoutException) && !ex.IsFatal())
            {
                throw AmqpClientHelper.ToIotHubClientContract(ex);
            }
        }
Example #3
0
        public override async Task <FileNotification> ReceiveAsync(TimeSpan timeout)
        {
            try
            {
                ReceivingAmqpLink receivingLink = await this.faultTolerantReceivingLink.GetReceivingLinkAsync();

                AmqpMessage amqpMessage = await receivingLink.ReceiveMessageAsync(timeout);

                if (amqpMessage != null)
                {
                    using (amqpMessage)
                    {
                        AmqpClientHelper.ValidateContentType(amqpMessage, CommonConstants.FileNotificationContentType);

                        var fileNotification = await AmqpClientHelper.GetObjectFromAmqpMessageAsync <FileNotification>(amqpMessage);

                        fileNotification.LockToken = new Guid(amqpMessage.DeliveryTag.Array).ToString();

                        return(fileNotification);
                    }
                }

                return(null);
            }
            catch (Exception exception)
            {
                if (exception.IsFatal())
                {
                    throw;
                }

                throw AmqpClientHelper.ToIotHubClientContract(exception);
            }
        }
        internal static async Task DisposeMessageAsync(FaultTolerantAmqpObject <ReceivingAmqpLink> faultTolerantReceivingLink, string lockToken, Outcome outcome, bool batchable)
        {
            var deliveryTag = IotHubConnection.ConvertToDeliveryTag(lockToken);

            Outcome disposeOutcome;

            try
            {
                ReceivingAmqpLink deviceBoundReceivingLink = await faultTolerantReceivingLink.GetReceivingLinkAsync().ConfigureAwait(false);

                disposeOutcome = await deviceBoundReceivingLink.DisposeMessageAsync(deliveryTag, outcome, batchable, IotHubConnection.DefaultOperationTimeout).ConfigureAwait(false);
            }
            catch (Exception exception)
            {
                if (exception.IsFatal())
                {
                    throw;
                }

                throw AmqpClientHelper.ToIotHubClientContract(exception);
            }

            if (disposeOutcome.DescriptorCode != Accepted.Code)
            {
                throw AmqpErrorMapper.GetExceptionFromOutcome(disposeOutcome);
            }
        }
        async Task DisposeMessageAsync(string lockToken, Outcome outcome)
        {
            var deliveryTag = IotHubConnection.ConvertToDeliveryTag(lockToken);

            Outcome disposeOutcome;

            try
            {
                ReceivingAmqpLink deviceBoundReceivingLink = await this.GetReceivingLinkAsync();

                disposeOutcome = await deviceBoundReceivingLink.DisposeMessageAsync(deliveryTag, outcome, batchable : true, timeout : this.OperationTimeout);
            }
            catch (Exception exception)
            {
                if (exception.IsFatal())
                {
                    throw;
                }

                throw AmqpClientHelper.ToIotHubClientContract(exception);
            }

            if (disposeOutcome.DescriptorCode != Accepted.Code)
            {
                throw AmqpErrorMapper.GetExceptionFromOutcome(disposeOutcome);
            }
        }
Example #6
0
 public override Task CompleteAsync(FileNotification fileNotification)
 {
     return(AmqpClientHelper.DisposeMessageAsync(
                this.faultTolerantReceivingLink,
                fileNotification.LockToken,
                AmqpConstants.AcceptedOutcome,
                false));
 }
Example #7
0
 public override Task AbandonAsync(FeedbackBatch feedback)
 {
     return(AmqpClientHelper.DisposeMessageAsync(
                _faultTolerantReceivingLink,
                feedback.LockToken,
                AmqpConstants.ReleasedOutcome,
                true));
 }
Example #8
0
 public AmqpFeedbackReceiver(IotHubConnection iotHubConnection)
 {
     Connection                  = iotHubConnection;
     OpenTimeout                 = IotHubConnection.DefaultOpenTimeout;
     OperationTimeout            = IotHubConnection.DefaultOperationTimeout;
     _receivingPath              = AmqpClientHelper.GetReceivingPath(EndpointKind.Feedback);
     _faultTolerantReceivingLink = new FaultTolerantAmqpObject <ReceivingAmqpLink>(CreateReceivingLinkAsync, Connection.CloseLink);
 }
 public override Task CompleteAsync(FeedbackBatch feedback)
 {
     return(AmqpClientHelper.DisposeMessageAsync(
                this.faultTolerantReceivingLink,
                feedback.LockToken,
                AmqpConstants.AcceptedOutcome,
                true));
 }
Example #10
0
 public override Task AbandonAsync(FileNotification fileNotification)
 {
     return(AmqpClientHelper.DisposeMessageAsync(
                _faultTolerantReceivingLink,
                fileNotification.LockToken,
                AmqpConstants.ReleasedOutcome,
                false));
 }
Example #11
0
 public AmqpFileNotificationReceiver(IotHubConnection iotHubConnection)
 {
     this.Connection                 = iotHubConnection;
     this.OpenTimeout                = IotHubConnection.DefaultOpenTimeout;
     this.OperationTimeout           = IotHubConnection.DefaultOperationTimeout;
     this.receivingPath              = AmqpClientHelper.GetReceivingPath(EndpointKind.FileNotification);
     this.faultTolerantReceivingLink = new FaultTolerantAmqpObject <ReceivingAmqpLink>(this.CreateReceivingLinkAsync, this.Connection.CloseLink);
 }
 public override Task AbandonAsync(FeedbackBatch feedback)
 {
     return(AmqpClientHelper.DisposeMessageAsync(
                _faultTolerantReceivingLink,
                feedback.LockToken,
                AmqpConstants.ReleasedOutcome,
                false)); // Feedback messages are sent by the service one at a time, so batching the acks is pointless
 }
 public override Task CompleteAsync(FeedbackBatch feedback, CancellationToken cancellationToken)
 {
     return(AmqpClientHelper.DisposeMessageAsync(
                _faultTolerantReceivingLink,
                feedback.LockToken,
                AmqpConstants.AcceptedOutcome,
                false, // Feedback messages are sent by the service one at a time, so batching the acks is pointless
                cancellationToken));
 }
        public override async Task <FeedbackBatch> ReceiveAsync(CancellationToken cancellationToken)
        {
            Logging.Enter(this, nameof(ReceiveAsync));

            try
            {
                cancellationToken.ThrowIfCancellationRequested();

                ReceivingAmqpLink receivingLink = await _faultTolerantReceivingLink.GetReceivingLinkAsync().ConfigureAwait(false);

                AmqpMessage amqpMessage = await receivingLink.ReceiveMessageAsync(cancellationToken).ConfigureAwait(false);

                Logging.Info(this, $"Message received is [{amqpMessage}]", nameof(ReceiveAsync));

                if (amqpMessage != null)
                {
                    using (amqpMessage)
                    {
                        AmqpClientHelper.ValidateContentType(amqpMessage, CommonConstants.BatchedFeedbackContentType);
                        IEnumerable <FeedbackRecord> records = await AmqpClientHelper
                                                               .GetObjectFromAmqpMessageAsync <IEnumerable <FeedbackRecord> >(amqpMessage).ConfigureAwait(false);

                        return(new FeedbackBatch
                        {
                            EnqueuedTime = (DateTime)amqpMessage.MessageAnnotations.Map[MessageSystemPropertyNames.EnqueuedTime],
                            LockToken = new Guid(amqpMessage.DeliveryTag.Array).ToString(),
                            Records = records,
                            UserId = Encoding.UTF8.GetString(amqpMessage.Properties.UserId.Array, amqpMessage.Properties.UserId.Offset, amqpMessage.Properties.UserId.Count)
                        });
                    }
                }

                return(null);
            }
            catch (Exception exception)
            {
                Logging.Error(this, exception, nameof(ReceiveAsync));

                if (exception.IsFatal())
                {
                    throw;
                }

                throw AmqpClientHelper.ToIotHubClientContract(exception);
            }
            finally
            {
                Logging.Exit(this, nameof(ReceiveAsync));
            }
        }
Example #15
0
        public async override Task SendAsync(string deviceId, Message message, TimeSpan?timeout = null)
        {
            if (string.IsNullOrWhiteSpace(deviceId))
            {
                throw new ArgumentException("Value should be non null and non empty", "deviceId");
            }

            if (message == null)
            {
                throw new ArgumentNullException("message");
            }
            Outcome outcome;

            using (AmqpMessage amqpMessage = message.ToAmqpMessage())
            {
                amqpMessage.Properties.To = "/devices/" + WebUtility.UrlEncode(deviceId) + "/messages/deviceBound";
                try
                {
                    SendingAmqpLink sendingLink = await GetSendingLinkAsync().ConfigureAwait(false);

                    if (timeout != null)
                    {
                        outcome = await sendingLink.SendMessageAsync(amqpMessage, IotHubConnection.GetNextDeliveryTag(ref sendingDeliveryTag), AmqpConstants.NullBinary, (TimeSpan)timeout).ConfigureAwait(false);
                    }
                    else
                    {
                        outcome = await sendingLink.SendMessageAsync(amqpMessage, IotHubConnection.GetNextDeliveryTag(ref sendingDeliveryTag), AmqpConstants.NullBinary, OperationTimeout).ConfigureAwait(false);
                    }
                }
                catch (TimeoutException exception)
                {
                    throw exception;
                }
                catch (Exception exception)
                {
                    if (exception.IsFatal())
                    {
                        throw;
                    }

                    throw AmqpClientHelper.ToIotHubClientContract(exception);
                }
            }
            if (outcome.DescriptorCode != Accepted.Code)
            {
                throw AmqpErrorMapper.GetExceptionFromOutcome(outcome);
            }
        }
        public override async Task <FeedbackBatch> ReceiveAsync(TimeSpan timeout)
        {
            try
            {
                ReceivingAmqpLink receivingLink = await this.GetReceivingLinkAsync();

                AmqpMessage amqpMessage = await receivingLink.ReceiveMessageAsync(timeout);

                if (amqpMessage != null)
                {
                    using (amqpMessage)
                    {
                        string contentType = amqpMessage.Properties.ContentType.ToString();
                        if (!string.Equals(contentType, CommonConstants.BatchedFeedbackContentType, StringComparison.OrdinalIgnoreCase))
                        {
                            throw new InvalidOperationException("Unsupported content type: {0}".FormatInvariant(contentType));
                        }

                        using (var reader = new StreamReader(amqpMessage.BodyStream, Encoding.UTF8))
                        {
                            string jsonString = await reader.ReadToEndAsync();

                            var records = JsonConvert.DeserializeObject <IEnumerable <FeedbackRecord> >(jsonString);

                            return(new FeedbackBatch
                            {
                                EnqueuedTime = (DateTime)amqpMessage.MessageAnnotations.Map[MessageSystemPropertyNames.EnqueuedTime],
                                LockToken = new Guid(amqpMessage.DeliveryTag.Array).ToString(),
                                Records = records,
                                UserId = Encoding.UTF8.GetString(amqpMessage.Properties.UserId.Array, amqpMessage.Properties.UserId.Offset, amqpMessage.Properties.UserId.Count)
                            });
                        }
                    }
                }

                return(null);
            }
            catch (Exception exception)
            {
                if (exception.IsFatal())
                {
                    throw;
                }

                throw AmqpClientHelper.ToIotHubClientContract(exception);
            }
        }
Example #17
0
        public override async Task <FileNotification> ReceiveAsync(CancellationToken cancellationToken)
        {
            Logging.Enter(this, nameof(ReceiveAsync));

            try
            {
                cancellationToken.ThrowIfCancellationRequested();

                ReceivingAmqpLink receivingLink = await _faultTolerantReceivingLink.GetReceivingLinkAsync().ConfigureAwait(false);

                AmqpMessage amqpMessage = await receivingLink.ReceiveMessageAsync(cancellationToken).ConfigureAwait(false);

                Logging.Info(this, $"Message received is [{amqpMessage}]", nameof(ReceiveAsync));

                if (amqpMessage != null)
                {
                    using (amqpMessage)
                    {
                        AmqpClientHelper.ValidateContentType(amqpMessage, CommonConstants.FileNotificationContentType);

                        FileNotification fileNotification = await AmqpClientHelper.GetObjectFromAmqpMessageAsync <FileNotification>(amqpMessage).ConfigureAwait(false);

                        fileNotification.LockToken = new Guid(amqpMessage.DeliveryTag.Array).ToString();

                        return(fileNotification);
                    }
                }

                return(null);
            }
            catch (Exception exception)
            {
                Logging.Error(this, exception, nameof(ReceiveAsync));

                if (exception.IsFatal())
                {
                    throw;
                }

                throw AmqpClientHelper.ToIotHubClientContract(exception);
            }
            finally
            {
                Logging.Exit(this, nameof(ReceiveAsync));
            }
        }
Example #18
0
        public override async Task SendAsync(string deviceId, string moduleId, Message message)
        {
            if (string.IsNullOrWhiteSpace(deviceId))
            {
                throw new ArgumentNullException(nameof(deviceId));
            }

            if (string.IsNullOrWhiteSpace(moduleId))
            {
                throw new ArgumentNullException(nameof(moduleId));
            }

            if (message == null)
            {
                throw new ArgumentNullException(nameof(message));
            }

            Outcome outcome;

            using (AmqpMessage amqpMessage = message.ToAmqpMessage())
            {
                amqpMessage.Properties.To = "/devices/" + WebUtility.UrlEncode(deviceId) + "/modules/" + WebUtility.UrlEncode(moduleId) + "/messages/deviceBound";
                try
                {
                    SendingAmqpLink sendingLink = await this.GetSendingLinkAsync().ConfigureAwait(false);

                    outcome = await sendingLink.SendMessageAsync(amqpMessage, IotHubConnection.GetNextDeliveryTag(ref this.sendingDeliveryTag), AmqpConstants.NullBinary, this.OperationTimeout).ConfigureAwait(false);
                }
                catch (Exception exception)
                {
                    if (exception.IsFatal())
                    {
                        throw;
                    }

                    throw AmqpClientHelper.ToIotHubClientContract(exception);
                }
            }

            if (outcome.DescriptorCode != Accepted.Code)
            {
                throw AmqpErrorMapper.GetExceptionFromOutcome(outcome);
            }
        }
        public override async Task <FeedbackBatch> ReceiveAsync(TimeSpan timeout)
        {
            try
            {
                ReceivingAmqpLink receivingLink = await faultTolerantReceivingLink.GetReceivingLinkAsync().ConfigureAwait(false);

                AmqpMessage amqpMessage = await receivingLink.ReceiveMessageAsync(timeout).ConfigureAwait(false);

                if (amqpMessage != null)
                {
                    using (amqpMessage)
                    {
                        AmqpClientHelper.ValidateContentType(amqpMessage, CommonConstants.BatchedFeedbackContentType);
                        var records = await AmqpClientHelper.GetObjectFromAmqpMessageAsync <IEnumerable <FeedbackRecord> >(amqpMessage).ConfigureAwait(false);

                        return(new FeedbackBatch
                        {
                            EnqueuedTime = (DateTime)amqpMessage.MessageAnnotations.Map[MessageSystemPropertyNames.EnqueuedTime],
                            LockToken = new Guid(amqpMessage.DeliveryTag.Array).ToString(),
                            Records = records,
                            UserId = Encoding.UTF8.GetString(amqpMessage.Properties.UserId.Array, amqpMessage.Properties.UserId.Offset, amqpMessage.Properties.UserId.Count)
                        });
                    }
                }

                return(null);
            }
            catch (Exception exception)
            {
                if (exception.IsFatal())
                {
                    throw;
                }

                throw AmqpClientHelper.ToIotHubClientContract(exception);
            }
        }
        private async Task <AmqpSession> CreateSessionAsync(TimeSpan timeout)
        {
            Logging.Enter(this, timeout, nameof(CreateSessionAsync));

            TransportBase transport = null;

            try
            {
                var timeoutHelper = new TimeoutHelper(timeout);
                _refreshTokenTimer.Cancel();

                AmqpSettings amqpSettings = CreateAmqpSettings();
                if (_useWebSocketOnly)
                {
                    // Try only AMQP transport over WebSocket
                    transport = _clientWebSocketTransport = (ClientWebSocketTransport) await CreateClientWebSocketTransportAsync(timeoutHelper.RemainingTime())
                                                            .ConfigureAwait(false);
                }
                else
                {
                    TlsTransportSettings tlsTransportSettings = CreateTlsTransportSettings();
                    var amqpTransportInitiator = new AmqpTransportInitiator(amqpSettings, tlsTransportSettings);
                    try
                    {
                        transport = await amqpTransportInitiator.ConnectTaskAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false);
                    }
                    catch (Exception e) when(!(e is AuthenticationException))
                    {
                        Logging.Error(this, e, nameof(CreateSessionAsync));

                        if (Fx.IsFatal(e))
                        {
                            throw;
                        }

                        // AMQP transport over TCP failed. Retry AMQP transport over WebSocket
                        if (timeoutHelper.RemainingTime() != TimeSpan.Zero)
                        {
                            transport = _clientWebSocketTransport = (ClientWebSocketTransport) await CreateClientWebSocketTransportAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false);
                        }
                        else
                        {
                            throw;
                        }
                    }
                }

                Logging.Info(this, $"Initialized {nameof(TransportBase)}, ws={_useWebSocketOnly}");

                var amqpConnectionSettings = new AmqpConnectionSettings
                {
                    MaxFrameSize = AmqpConstants.DefaultMaxFrameSize,
                    ContainerId  = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture), // Use a human readable link name to help with debugging
                    HostName     = ConnectionString.AmqpEndpoint.Host,
                };

                var amqpConnection = new AmqpConnection(transport, amqpSettings, amqpConnectionSettings);
                await amqpConnection.OpenAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false);

                Logging.Info(this, $"{nameof(AmqpConnection)} opened.");

                var sessionSettings = new AmqpSessionSettings
                {
                    Properties = new Fields(),
                };

                try
                {
                    AmqpSession amqpSession = amqpConnection.CreateSession(sessionSettings);
                    await amqpSession.OpenAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false);

                    Logging.Info(this, $"{nameof(AmqpSession)} opened.");

                    // This adds itself to amqpConnection.Extensions
                    var cbsLink = new AmqpCbsLink(amqpConnection);
                    await SendCbsTokenAsync(cbsLink, timeoutHelper.RemainingTime()).ConfigureAwait(false);

                    return(amqpSession);
                }
                catch (Exception ex) when(!ex.IsFatal())
                {
                    Logging.Error(this, ex, nameof(CreateSessionAsync));

                    _clientWebSocketTransport?.Dispose();
                    _clientWebSocketTransport = null;

                    if (amqpConnection.TerminalException != null)
                    {
                        throw AmqpClientHelper.ToIotHubClientContract(amqpConnection.TerminalException);
                    }

                    amqpConnection.SafeClose(ex);
                    throw;
                }
            }
            finally
            {
                Logging.Exit(this, timeout, nameof(CreateSessionAsync));
            }
        }
        async Task <AmqpSession> CreateSessionAsync(TimeSpan timeout)
        {
            TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);

            this.refreshTokenTimer.Cancel();

            var           amqpSettings = CreateAmqpSettings();
            TransportBase transport;

            if (this.useWebSocketOnly)
            {
                // Try only Amqp transport over WebSocket
                transport = await CreateClientWebSocketTransport(timeoutHelper.RemainingTime()).ConfigureAwait(false);
            }
            else
            {
                var tlsTransportSettings   = this.CreateTlsTransportSettings();
                var amqpTransportInitiator = new AmqpTransportInitiator(amqpSettings, tlsTransportSettings);
                try
                {
                    transport = await amqpTransportInitiator.ConnectTaskAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false);
                }
                catch (Exception e)
                {
                    if (Fx.IsFatal(e))
                    {
                        throw;
                    }

                    // Amqp transport over TCP failed. Retry Amqp transport over WebSocket
                    if (timeoutHelper.RemainingTime() != TimeSpan.Zero)
                    {
                        transport = await CreateClientWebSocketTransport(timeoutHelper.RemainingTime()).ConfigureAwait(false);
                    }
                    else
                    {
                        throw;
                    }
                }
            }

            AmqpConnectionSettings amqpConnectionSettings = new AmqpConnectionSettings()
            {
                MaxFrameSize = AmqpConstants.DefaultMaxFrameSize,
                ContainerId  = Guid.NewGuid().ToString("N"),
                HostName     = this.connectionString.AmqpEndpoint.Host
            };

            var amqpConnection = new AmqpConnection(transport, amqpSettings, amqpConnectionSettings);
            await amqpConnection.OpenAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false);

            var sessionSettings = new AmqpSessionSettings()
            {
                Properties = new Fields()
            };

            try
            {
                var amqpSession = amqpConnection.CreateSession(sessionSettings);
                await amqpSession.OpenAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false);

                // This adds itself to amqpConnection.Extensions
                var cbsLink = new AmqpCbsLink(amqpConnection);
                await SendCbsTokenAsync(cbsLink, timeoutHelper.RemainingTime()).ConfigureAwait(false);

                return(amqpSession);
            }
            catch (Exception ex) when(!ex.IsFatal())
            {
                if (amqpConnection.TerminalException != null)
                {
                    throw AmqpClientHelper.ToIotHubClientContract(amqpConnection.TerminalException);
                }

                amqpConnection.SafeClose(ex);
                throw;
            }
        }
        private async Task <AmqpSession> CreateSessionAsync(TimeSpan timeout)
        {
            var timeoutHelper = new TimeoutHelper(timeout);

            _refreshTokenTimer.Cancel();

            AmqpSettings  amqpSettings = CreateAmqpSettings();
            TransportBase transport;

            if (_useWebSocketOnly)
            {
                // Try only Amqp transport over WebSocket
                transport = await CreateClientWebSocketTransport(timeoutHelper.RemainingTime()).ConfigureAwait(false);
            }
            else
            {
                TlsTransportSettings tlsTransportSettings = CreateTlsTransportSettings();
                var amqpTransportInitiator = new AmqpTransportInitiator(amqpSettings, tlsTransportSettings);
                try
                {
                    transport = await amqpTransportInitiator.ConnectTaskAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false);
                }
#if !NETSTANDARD1_3
                catch (AuthenticationException)
                {
                    throw;
                }
#endif
                catch (Exception e)
                {
                    if (Fx.IsFatal(e))
                    {
                        throw;
                    }

                    // Amqp transport over TCP failed. Retry Amqp transport over WebSocket
                    if (timeoutHelper.RemainingTime() != TimeSpan.Zero)
                    {
                        transport = await CreateClientWebSocketTransport(timeoutHelper.RemainingTime()).ConfigureAwait(false);
                    }
                    else
                    {
                        throw;
                    }
                }
            }

            var amqpConnectionSettings = new AmqpConnectionSettings
            {
                MaxFrameSize = AmqpConstants.DefaultMaxFrameSize,
                ContainerId  = Guid.NewGuid()
#if NETSTANDARD1_3
                               .ToString("N"),
#else
                               .ToString("N", CultureInfo.InvariantCulture), // Use a human readable link name to help with debugging
#endif
                HostName = ConnectionString.AmqpEndpoint.Host,
            };

            var amqpConnection = new AmqpConnection(transport, amqpSettings, amqpConnectionSettings);
            await amqpConnection.OpenAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false);

            var sessionSettings = new AmqpSessionSettings
            {
                Properties = new Fields(),
            };

            try
            {
                AmqpSession amqpSession = amqpConnection.CreateSession(sessionSettings);
                await amqpSession.OpenAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false);

                // This adds itself to amqpConnection.Extensions
                var cbsLink = new AmqpCbsLink(amqpConnection);
                await SendCbsTokenAsync(cbsLink, timeoutHelper.RemainingTime()).ConfigureAwait(false);

                return(amqpSession);
            }
            catch (Exception ex) when(!ex.IsFatal())
            {
                if (amqpConnection.TerminalException != null)
                {
                    throw AmqpClientHelper.ToIotHubClientContract(amqpConnection.TerminalException);
                }

                amqpConnection.SafeClose(ex);
                throw;
            }
        }