Exemple #1
0
        /// <summary>
        /// Constructor.
        /// </summary>
        public MqttSubscriber(OnEntityUpdated onEntityUpdatedCallback, OnConnectionResult onConnectionResultCallback)
        {
            MqttFactory = new MqttFactory();
            MqttClient  = MqttFactory.CreateMqttClient();

            OnEntityUpdatedCallback    = onEntityUpdatedCallback ?? throw new ArgumentNullException(nameof(onEntityUpdatedCallback));
            OnConnectionResultCallback = onConnectionResultCallback ?? throw new ArgumentNullException(nameof(onConnectionResultCallback));

            // Handle message received callbacks
            MqttClient.UseApplicationMessageReceivedHandler(e =>
            {
                string entityId = $"{e.ApplicationMessage.Topic.Split('/')[1]}.{e.ApplicationMessage.Topic.Split('/')[2]}";

                Telemetry.TrackTrace(
                    nameof(MqttClient.ApplicationMessageReceivedHandler),
                    new Dictionary <string, string>
                {
                    [nameof(Entity.EntityId)] = entityId,
                });

                OnEntityUpdatedCallback();
            });

            // Handle subscription connection
            MqttClient.UseConnectedHandler(async e =>
            {
                MqttClientSubscribeResult result = await MqttClient.SubscribeAsync(new TopicFilterBuilder()
                                                                                   .WithTopic(SettingsControl.MqttTopic)
                                                                                   .Build());

                Telemetry.TrackEvent(
                    nameof(MqttClient.ConnectedHandler),
                    new Dictionary <string, string>
                {
                    [nameof(MqttClient.IsConnected)]        = MqttClient.IsConnected.ToString(),
                    [nameof(MqttClientSubscribeResultCode)] = result.Items.FirstOrDefault()?.ResultCode.ToString(),
                });

                OnConnectionResultCallback(MqttClient.IsConnected);
            });

            // Handle disconnects
            MqttClient.UseDisconnectedHandler(async e =>
            {
                // Only attempt to reconnect when desired
                if (AttemptReconnectOnDisconnect)
                {
                    Telemetry.TrackEvent(
                        nameof(MqttClient.DisconnectedHandler),
                        new Dictionary <string, string>(e.ToDictionary())
                    {
                        [nameof(MqttClient.IsConnected)] = MqttClient.IsConnected.ToString(),
                    });

                    await Task.Delay(TimeSpan.FromSeconds(1));

                    await Connect();
                }
            });
        }
Exemple #2
0
        private void HandleSubscriptionResult(MqttClientSubscribeResult subscribeResult, Subscription subscription)
        {
            var resultItem = subscribeResult.Items.First();

            switch (subscription.Qos)
            {
            case MqttQualityOfServiceLevel.AtMostOnce:
                LogOnError(resultItem.ResultCode, MqttClientSubscribeResultCode.GrantedQoS0);
                break;

            case MqttQualityOfServiceLevel.AtLeastOnce:
                LogOnError(resultItem.ResultCode, MqttClientSubscribeResultCode.GrantedQoS1);
                break;

            case MqttQualityOfServiceLevel.ExactlyOnce:
                LogOnError(resultItem.ResultCode, MqttClientSubscribeResultCode.GrantedQoS2);
                break;

            default: throw new ArgumentOutOfRangeException();
            }

            void LogOnError(MqttClientSubscribeResultCode actual, MqttClientSubscribeResultCode expected)
            {
                if (actual != expected)
                {
                    logger.LogMessage($"received result code {actual}, but expected {expected}",
                                      a => a
                                      .Add(nameof(subscription.Topic), subscription.Topic)
                                      .Add(nameof(subscription.Qos), subscription.Qos),
                                      LogLevel.Error);
                }
            }
        }
        /// <inheritdoc cref="IMqttClient.SubscribeAsync" />
        public Task <MqttClientSubscribeResult> SubscribeAsync(
            MqttClientSubscribeOptions options,
            CancellationToken cancellationToken)
        {
            Check.NotNull(options, nameof(options));

            _broker.Subscribe(ClientId, options.TopicFilters.Select(filter => filter.Topic).ToList());

            var result = new MqttClientSubscribeResult();

            options.TopicFilters.ForEach(filter => result.Items.Add(MapSubscribeResultItem(filter)));
            return(Task.FromResult(result));
        }
        public MqttClientSubscribeResult Subscribe(MqttSubscribePacket subscribePacket)
        {
            if (subscribePacket == null)
            {
                throw new ArgumentNullException(nameof(subscribePacket));
            }

            var result = new MqttClientSubscribeResult
            {
                ResponsePacket = new MqttSubAckPacket
                {
                    PacketIdentifier = subscribePacket.PacketIdentifier
                },

                CloseConnection = false
            };

            foreach (var topicFilter in subscribePacket.TopicFilters)
            {
                var interceptorContext = InterceptSubscribe(topicFilter);
                if (!interceptorContext.AcceptSubscription)
                {
                    result.ResponsePacket.SubscribeReturnCodes.Add(MqttSubscribeReturnCode.Failure);
                }
                else
                {
                    result.ResponsePacket.SubscribeReturnCodes.Add(ConvertToMaximumQoS(topicFilter.QualityOfServiceLevel));
                }

                if (interceptorContext.CloseConnection)
                {
                    result.CloseConnection = true;
                }

                if (interceptorContext.AcceptSubscription)
                {
                    lock (_subscriptions)
                    {
                        _subscriptions[topicFilter.Topic] = topicFilter.QualityOfServiceLevel;
                    }

                    _eventDispatcher.OnClientSubscribedTopic(_clientId, topicFilter);
                }
            }

            return(result);
        }
        private void EnsureSubscriptionSuccessful([NotNull] MqttClientSubscribeResult result)
        {
            if (result == null)
            {
                throw new ArgumentNullException(nameof(result));
            }
            if (result.Items.Count == 0)
            {
                throw new ArgumentException("No items returned!", nameof(result));
            }
            var failed = result.Items.Where(i => !SuccessfulSubscriptionResultCodes.Contains(i.ResultCode)).ToList();

            if (failed.Any())
            {
                throw new ArgumentException("Client returned a set of unsuccessful subscriptions!")
                      {
                          Data = { { "Failed items", failed } }
                      };
            }
        }
Exemple #6
0
        public MqttClientSubscribeResult CreateClientSubscribeResult(MqttSubscribePacket subscribePacket, MqttSubAckPacket subAckPacket)
        {
            if (subscribePacket == null)
            {
                throw new ArgumentNullException(nameof(subscribePacket));
            }
            if (subAckPacket == null)
            {
                throw new ArgumentNullException(nameof(subAckPacket));
            }

            if (subAckPacket.ReasonCodes.Count != subscribePacket.TopicFilters.Count)
            {
                throw new MqttProtocolViolationException("The reason codes are not matching the topic filters [MQTT-3.9.3-1].");
            }

            var result = new MqttClientSubscribeResult();

            result.Items.AddRange(subscribePacket.TopicFilters.Select((t, i) =>
                                                                      new MqttClientSubscribeResultItem(t, (MqttClientSubscribeResultCode)subAckPacket.ReasonCodes[i])));

            return(result);
        }
Exemple #7
0
 public async Task TestMqttSubscription()
 {
     MqttClientSubscribeResult res = await client.SubscribeAsync("gh/tv");
 }
        /// <summary>
        /// Constructor.
        /// </summary>
        public MqttSubscriber(
            OnEnablementUpdatedCallback onEnablementUpdatedCallback,
            OnLightLevelUpdated onLightLevelUpdatedCallback,
            OnFluxStatusUpdatedCallback onFluxStatusUpdatedCallback)
        {
            if (null == onEnablementUpdatedCallback)
            {
                throw new ArgumentNullException(nameof(onEnablementUpdatedCallback));
            }

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

            MqttFactory = new MqttFactory();
            MqttClient  = MqttFactory.CreateMqttClient();

            // Handle callbacks
            MqttClient.UseApplicationMessageReceivedHandler(e =>
            {
                try
                {
                    string utfString = Encoding.UTF8.GetString(e.ApplicationMessage.Payload, 0, e.ApplicationMessage.Payload.Length);

                    if (e.ApplicationMessage.Topic.Equals($"{MqttConfig.Topic}/set", StringComparison.OrdinalIgnoreCase))
                    {
                        bool enable = Convert.ToBoolean(utfString);
                        onEnablementUpdatedCallback(enable);
                    }
                    else if (e.ApplicationMessage.Topic.Equals($"{MqttConfig.Topic}/lightlevel", StringComparison.OrdinalIgnoreCase))
                    {
                        double lightLevel = Convert.ToDouble(utfString);
                        onLightLevelUpdatedCallback(lightLevel);
                    }
                    else if (e.ApplicationMessage.Topic.Equals($"{MqttConfig.Topic}/status", StringComparison.OrdinalIgnoreCase))
                    {
                        FluxStatus fluxStatus = JsonConvert.DeserializeObject <FluxStatus>(utfString);
                        onFluxStatusUpdatedCallback(fluxStatus.Brightness, fluxStatus.ColorTemperature);
                    }
                }
                catch (Exception)
                {
                }
            });

            // Handle subscription connection
            MqttClient.UseConnectedHandler(async e =>
            {
                Log.Debug($"{nameof(MqttSubscriber)} is connected. Attempting to subscribe to topic '{MqttConfig.Topic}'.");

                // Subscribe to the desired topic when connected
                MqttClientSubscribeResult result = await MqttClient.SubscribeAsync(new TopicFilterBuilder()
                                                                                   .WithTopic($"{MqttConfig.Topic}/#")
                                                                                   .Build());
            });

            // Handle disconnects
            MqttClient.UseDisconnectedHandler(async e =>
            {
                Log.Debug($"{nameof(MqttSubscriber)} is disconnected. Attempting to reconnect.");

                // Allow time for network connectivy hiccups to be resolved before trying again.
                await Task.Delay(TimeSpan.FromSeconds(1));

                // Reconnect when disconnected
                Connect();
            });
        }
Exemple #9
0
        public RemoteMqttBroker(
            ILogger <RemoteMqttBroker> logger,
            IEventIdCreationSource eventIdCreationSource,
            string host,
            int port,
            int timeout)
        {
            _logger = logger;
            _eventIdCreationSource = eventIdCreationSource;

            EventId eventId = GetNextEventId();

#if DEBUG
            _logger.LogDebug(eventId, "Creating Mqtt Client.");
#endif
            if (port < 0x0000)
            {
                throw new ArgumentOutOfRangeException(nameof(port), port, "Port number too small.");
            }
            else if (timeout > 0xffff)
            {
                throw new ArgumentOutOfRangeException(nameof(port), port, "Port number too large.");
            }

            if (timeout < 1)
            {
                throw new ArgumentOutOfRangeException(nameof(timeout), timeout, "Timeout timespan too small.");
            }
            else if (timeout > 99999)
            {
                throw new ArgumentOutOfRangeException(nameof(timeout), timeout, "Timeout timespan too large.");
            }

            _logger.LogInformation(eventId, $"MQTT Client Communication Timeout: {timeout} ms.");

            var clientOptionsBuilder = new MqttClientOptionsBuilder()
                                       .WithClientId(ClientId)
                                       .WithCommunicationTimeout(TimeSpan.FromMilliseconds(timeout))
                                       .WithTcpServer(host, port);

            _mqttClient = new MqttFactory().CreateMqttClient();

            CancellationTokenSource?cancellationTokenSource = null;

            #region Connecting to remote Mqtt Broker

            try
            {
                _logger.LogInformation(eventId, $"Connecting to remote Mqtt-Broker (mqtt://{host}:{port}).");

                cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(5)); //timeout
                var result = _mqttClient.ConnectAsync(clientOptionsBuilder.Build(), cancellationTokenSource.Token).GetAwaiter().GetResult();

                if (result.ResultCode != MqttClientConnectResultCode.Success)
                {
                    throw new Exception("Mqtt-Client ConnectResultCode Success expected. Actual: " + result.ResultCode);
                }
            }
            catch (OperationCanceledException)
            {
                string errorMessage = "Connect to remote Mqtt-Broker timed out.";
                _logger.LogCritical(eventId, errorMessage);
                throw new Exception(errorMessage);
            }
            catch (Exception exception)
            {
                string errorMessage = "Failed to connect to remote Mqtt-Broker.";
                _logger.LogCritical(eventId, exception, errorMessage);
                throw new Exception(errorMessage);
            }
            finally
            {
                cancellationTokenSource?.Dispose();
            }

            #endregion

            #region Subscribing to relevant Events

            try
            {
                _logger.LogInformation(eventId, $"Subscribing to relevant events.");

                MqttQualityOfServiceLevel     mqttQualityOfServiceLevel   = MqttQualityOfServiceLevel.AtLeastOnce;
                MqttClientSubscribeResultCode expectedSubscribeResultCode = MqttClientSubscribeResultCode.GrantedQoS1;

                MqttClientSubscribeOptionsBuilder subscribeOptionsBuilder = new MqttClientSubscribeOptionsBuilder()
                                                                            .WithTopicFilter(MqttTopics.ClientJoinRequested, mqttQualityOfServiceLevel)
                                                                            .WithTopicFilter(MqttTopics.ClientJoinSucceeded, mqttQualityOfServiceLevel)
                                                                            .WithTopicFilter(MqttTopics.ClientJoinFailed, mqttQualityOfServiceLevel)
                                                                            .WithTopicFilter(MqttTopics.ClientGoodbye, mqttQualityOfServiceLevel)
                                                                            .WithTopicFilter(MqttTopics.FragmentDistributionRequested, mqttQualityOfServiceLevel)
                                                                            .WithTopicFilter(MqttTopics.FragmentDistributionObtained, mqttQualityOfServiceLevel)
                                                                            .WithTopicFilter(MqttTopics.FragmentDistributionFailed, mqttQualityOfServiceLevel);

                cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(5)); //timeout
                MqttClientSubscribeResult result = _mqttClient.SubscribeAsync(subscribeOptionsBuilder.Build(), cancellationTokenSource.Token).GetAwaiter().GetResult();

                foreach (MqttClientSubscribeResultItem item in result.Items)
                {
                    if (item.ResultCode != expectedSubscribeResultCode)
                    {
                        throw new Exception($"Expected SubscribeResultCode {expectedSubscribeResultCode} for topic \"{item.TopicFilter.Topic}\". Actual: {item.ResultCode}");
                    }
                }
            }
            catch (OperationCanceledException)
            {
                string errorMessage = "Subscribing to all relevant Events to remote Mqtt-Broker timed out.";
                _logger.LogCritical(eventId, errorMessage);

                DisconnectOnError(errorMessage);

                throw new Exception(errorMessage);
            }
            catch (Exception exception)
            {
                string errorMessage = "Failed to subscribe to all relevant topics with expected SubscribeResultCode.";
                _logger.LogCritical(eventId, exception, errorMessage);

                DisconnectOnError(errorMessage);

                throw new Exception(errorMessage);
            }
            finally
            {
                cancellationTokenSource?.Dispose();
            }

            #endregion

            void DisconnectOnError(string reasonString)
            {
                try
                {
                    _logger.LogInformation("Disconnecting from remote Mqtt-Broker");
                    MqttClientDisconnectOptions disconnectOptions = new MqttClientDisconnectOptions()
                    {
                        ReasonCode   = MqttClientDisconnectReason.NormalDisconnection,
                        ReasonString = reasonString
                    };

                    cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(5));
                    _mqttClient.DisconnectAsync(disconnectOptions, cancellationTokenSource.Token).GetAwaiter().GetResult();
                }
                catch (OperationCanceledException)
                {
                    _logger.LogError(eventId, "Disconnecting from remote Mqtt-Broker timed out.");
                }
                catch (Exception exception)
                {
                    _logger.LogError(eventId, exception, "Disconnecting from remote Mqtt-Broker failed.");
                }
                finally
                {
                    cancellationTokenSource?.Dispose();
                }
            }
        }
Exemple #10
0
        public async Task <bool> AddSubscription(GraphQLQuery query, Action callbackMethod)
        {
            HttpContent         httpContent = new StringContent(query.getPayload(), Encoding.UTF8, "application/json");
            HttpResponseMessage response    = await httpClient.PostAsync(httpEndpoint, httpContent);

            response.EnsureSuccessStatusCode();

            Stream stream = await response.Content.ReadAsStreamAsync();

            SubscriptionHttpResponseModel result = DeserializeJsonFromStream <SubscriptionHttpResponseModel>(stream);

            Console.WriteLine(JsonConvert.SerializeObject(result));

            Uri    wsUri    = null;
            string clientId = null;
            string topic    = result.extensions.subscription.newSubscriptions["onUpdateCharacter"]["topic"];

            foreach (var conn in result.extensions.subscription.mqttConnections)
            {
                if (wsUri == null)
                {
                    foreach (var t in conn.topics)
                    {
                        if (String.Equals(topic, t))
                        {
                            wsUri    = new Uri(conn.url);
                            clientId = conn.client;
                            Console.WriteLine("Topic == " + t);
                            break;
                        }
                        else
                        {
                            Console.WriteLine("Topic != " + t);
                        }
                    }
                }
            }
            if (wsUri == null)
            {
                Console.WriteLine("wsUri still null");
            }

            string wsEndpoint = wsUri.Host + wsUri.PathAndQuery + wsUri.Fragment;

            var factory    = new MqttFactory();
            var mqttClient = factory.CreateMqttClient();
            var options    = new MqttClientOptionsBuilder()
                             .WithWebSocketServer(wsEndpoint)
                             .WithTls()
                             .WithClientId(clientId)
                             .Build();

            Console.WriteLine(JsonConvert.SerializeObject(options));
            MQTTnet.Client.Connecting.MqttClientAuthenticateResult r0 = mqttClient.ConnectAsync(options, CancellationToken.None).Result;
            Console.WriteLine("MQTT Connect: " + r0.ResultCode.ToString());

            mqttClient.UseApplicationMessageReceivedHandler(e =>
            {
                Console.ForegroundColor = ConsoleColor.Green;
                Console.WriteLine("Received message:");
                Console.WriteLine($"+ Payload = {Encoding.UTF8.GetString(e.ApplicationMessage.Payload)}");
                Console.WriteLine();
                Console.ResetColor();
            });

            MqttClientSubscribeResult r1 = mqttClient.SubscribeAsync(new TopicFilterBuilder().WithTopic(topic).Build()).Result;

            Console.WriteLine("MQTT Subscription: " + r1.Items.ToString());
            while (true)
            {
            }


/*
 *          mqttClient.UseConnectedHandler(async e =>
 *          {
 *              Console.WriteLine("Connected with server!");
 *              await mqttClient.SubscribeAsync(new TopicFilterBuilder().WithTopic(topic).Build());
 *              Console.WriteLine("Subscribed!");
 *
 *          });
 */
            return(true);

            // TODO: Return something about the callback?
        }
 protected virtual void OnSubscribed(MqttClientSubscribeResult subscription)
 {
 }
Exemple #12
0
        public static MqttStatus Subscribe(Guid key, string topic, string gxproc, int qos)
        {
            try
            {
                if (string.IsNullOrEmpty(gxproc))
                {
                    throw new ArgumentNullException(nameof(gxproc), "GeneXus procedure parameter cannot be null");
                }

                string fullPath = gxproc;
                if (!Path.IsPathRooted(gxproc))
                {
                    string fileName = $"a{gxproc}.dll";
                    string baseDir  = !string.IsNullOrEmpty(AppDomain.CurrentDomain.RelativeSearchPath) ? AppDomain.CurrentDomain.RelativeSearchPath : AppDomain.CurrentDomain.BaseDirectory;
                    fullPath = Path.Combine(baseDir, fileName);
                }

                if (!File.Exists(fullPath))
                {
                    throw new FileNotFoundException($"File not found at {fullPath}", fullPath);
                }

                MqttClient mqtt = GetClient(key);

                if (topic.Contains("*") || topic.Contains("+") || topic.Contains("#"))
                {
                    if (!mqtt.m_config.AllowWildcardsInTopicFilters)
                    {
                        throw new InvalidDataException("Wildcards not allowed for this instance.");
                    }
                }

                MqttClientSubscribeOptions options = new MqttClientSubscribeOptions
                {
                    //TopicFilters = new List<MqttTopicFilter> { new MqttTopicFilter() { Topic = topic, QualityOfServiceLevel = (MQTTnet.Protocol.MqttQualityOfServiceLevel)Enum.ToObject(typeof(MQTTnet.Protocol.MqttQualityOfServiceLevel), qos) } },
                    TopicFilters = new List <TopicFilter> {
                        new TopicFilter()
                        {
                            Topic = topic, QualityOfServiceLevel = (MQTTnet.Protocol.MqttQualityOfServiceLevel)Enum.ToObject(typeof(MQTTnet.Protocol.MqttQualityOfServiceLevel), qos)
                        }
                    },
                    UserProperties = new List <MqttUserProperty> {
                        new MqttUserProperty("gxrocedure", $"{{\"gxrocedure\":\"{gxproc}\"}}")
                    }
                };

                if (mqtt.m_mqttClient.ApplicationMessageReceivedHandler == null)
                {
                    mqtt.m_mqttClient.UseApplicationMessageReceivedHandler(mqtt.ProcessMessage);
                }

                MqttClientSubscribeResult result = mqtt.m_mqttClient.SubscribeAsync(options).GetAwaiter().GetResult();
                mqtt.AddTopic(topic, fullPath);                // GetClient s_topicProcs[GetProcKey(mqtt, topic)] = gxproc;
            }
            catch (Exception ex)
            {
                return(MqttStatus.Fail(key, ex));
            }

            return(MqttStatus.Success(key));
        }
Exemple #13
0
        public RemoteMqttBroker(
            ILogger <RemoteMqttBroker> logger,
            IEventIdCreationSource eventIdCreationSource,
            IOptions <MqttNetworkOptions>?options = null)
        {
            _logger = logger;
            _eventIdCreationSource = eventIdCreationSource;

            EventId eventId = GetNextEventId();

            _logger.LogInformation(eventId, $"Creating Mqtt Client (Id: {ClientId}).");

            MqttNetworkOptions mqttNetworkOptions = options?.Value ?? MqttNetworkOptions.Default;

            mqttNetworkOptions.Host ??= MqttNetworkOptions.Default.Host !;

            if (mqttNetworkOptions.Port < 0x0000)
            {
                throw new ArgumentOutOfRangeException(nameof(mqttNetworkOptions.Port), mqttNetworkOptions.Port, "Port number too small.");
            }
            else if (mqttNetworkOptions.Port > 0xffff)
            {
                throw new ArgumentOutOfRangeException(nameof(mqttNetworkOptions.Port), mqttNetworkOptions.Port, "Port number too large.");
            }

            if (mqttNetworkOptions.Timeout < 1)
            {
                throw new ArgumentOutOfRangeException(nameof(mqttNetworkOptions.Timeout), mqttNetworkOptions.Timeout, "Timeout timespan too small.");
            }
            else if (mqttNetworkOptions.Timeout > 99999)
            {
                throw new ArgumentOutOfRangeException(nameof(mqttNetworkOptions.Timeout), mqttNetworkOptions.Timeout, "Timeout timespan too large.");
            }

            _logger.LogInformation(eventId, $"MQTT Client Communication Timeout: {mqttNetworkOptions.Timeout} ms.");

            var clientOptionsBuilder = new MqttClientOptionsBuilder()
                                       .WithClientId(ClientId)
                                       .WithCommunicationTimeout(TimeSpan.FromSeconds(60))
                                       .WithTcpServer(mqttNetworkOptions.Host, mqttNetworkOptions.Port);

            _mqttClient = new MqttFactory().CreateMqttClient();
            _mqttClient.ConnectedHandler = new MqttClientConnectedHandlerDelegate(eventArgs =>
            {
                _logger.LogDebug("Client Connected. Reason: " + (eventArgs.AuthenticateResult?.ReasonString ?? "null"));
            });

            _mqttClient.DisconnectedHandler = new MqttClientDisconnectedHandlerDelegate(eventArgs =>
            {
                _logger.LogDebug(eventArgs.Exception, "Client Disconnected. Reason: " + (eventArgs.AuthenticateResult?.ReasonString ?? "null"));
            });

            CancellationTokenSource?cancellationTokenSource = null;

            #region Connecting to remote Mqtt Broker

            try
            {
                _logger.LogInformation(eventId, $"Connecting to remote Mqtt-Broker (mqtt://{mqttNetworkOptions.Host}:{mqttNetworkOptions.Port}).");

                cancellationTokenSource = new CancellationTokenSource(TimeoutTimeSpan);
                var result = _mqttClient.ConnectAsync(clientOptionsBuilder.Build(), cancellationTokenSource.Token).GetAwaiter().GetResult();

                if (result.ResultCode != MqttClientConnectResultCode.Success)
                {
                    throw new Exception("Mqtt-Client ConnectResultCode Success expected. Actual: " + result.ResultCode);
                }
            }
            catch (OperationCanceledException)
            {
                string errorMessage = "Connect to remote Mqtt-Broker timed out.";
                _logger.LogCritical(eventId, errorMessage);
                throw new Exception(errorMessage);
            }
            catch (Exception exception)
            {
                string errorMessage = "Failed to connect to remote Mqtt-Broker.";
                _logger.LogCritical(eventId, exception, errorMessage);
                throw new Exception(errorMessage);
            }
            finally
            {
                cancellationTokenSource?.Dispose();
            }

            #endregion

            #region Subscribing to relevant Events

            try
            {
                _logger.LogInformation(eventId, $"Subscribing to relevant events.");

                MqttQualityOfServiceLevel     mqttQualityOfServiceLevel   = MqttQualityOfServiceLevel.AtLeastOnce;
                MqttClientSubscribeResultCode expectedSubscribeResultCode = MqttClientSubscribeResultCode.GrantedQoS1;

                MqttClientSubscribeOptionsBuilder subscribeOptionsBuilder = new MqttClientSubscribeOptionsBuilder()
                                                                            .WithTopicFilter(MqttTopics.TrackerHello, mqttQualityOfServiceLevel)
                                                                            .WithTopicFilter(MqttTopics.TrackerGoodbye, mqttQualityOfServiceLevel)
                                                                            .WithTopicFilter(MqttTopics.ClientJoinAccepted, mqttQualityOfServiceLevel)
                                                                            .WithTopicFilter(MqttTopics.ClientJoinDenied, mqttQualityOfServiceLevel)
                                                                            .WithTopicFilter(MqttTopics.ClientRegistered, mqttQualityOfServiceLevel)
                                                                            .WithTopicFilter(MqttTopics.ClientGoodbye, mqttQualityOfServiceLevel)
                                                                            .WithTopicFilter(MqttTopics.FileInfoPublished, mqttQualityOfServiceLevel)
                                                                            .WithTopicFilter(MqttTopics.FragmentDistributionStarted, mqttQualityOfServiceLevel)
                                                                            .WithTopicFilter(MqttTopics.FragmentDistributionDelivered, mqttQualityOfServiceLevel)
                                                                            .WithTopicFilter(MqttTopics.FragmentDistributionEnded, mqttQualityOfServiceLevel);

                cancellationTokenSource = new CancellationTokenSource(TimeoutTimeSpan); //timeout
                MqttClientSubscribeResult result = _mqttClient.SubscribeAsync(subscribeOptionsBuilder.Build(), cancellationTokenSource.Token).GetAwaiter().GetResult();

                foreach (MqttClientSubscribeResultItem item in result.Items)
                {
                    if (item.ResultCode != expectedSubscribeResultCode)
                    {
                        throw new Exception($"Expected SubscribeResultCode {expectedSubscribeResultCode} for topic \"{item.TopicFilter.Topic}\". Actual: {item.ResultCode}");
                    }
                }
            }
            catch (Exception exception)
            {
                string errorMessage;

                if (exception is OperationCanceledException)
                {
                    errorMessage = "Subscribing to all relevant Events to remote Mqtt-Broker timed out.";
                    _logger.LogCritical(eventId, errorMessage);
                }
                else
                {
                    errorMessage = "Failed to subscribe to all relevant topics with expected SubscribeResultCode.";
                    _logger.LogCritical(eventId, exception, errorMessage);
                }

                try
                {
                    _logger.LogInformation("Disconnecting from remote Mqtt-Broker");
                    MqttClientDisconnectOptions disconnectOptions = new MqttClientDisconnectOptions()
                    {
                        ReasonCode   = MqttClientDisconnectReason.NormalDisconnection,
                        ReasonString = errorMessage
                    };

                    cancellationTokenSource = new CancellationTokenSource(TimeoutTimeSpan);
                    _mqttClient.DisconnectAsync(disconnectOptions, cancellationTokenSource.Token).GetAwaiter().GetResult();
                }
                catch (OperationCanceledException)
                {
                    _logger.LogError(eventId, "Disconnecting from remote Mqtt-Broker timed out.");
                }
                catch (Exception disconnectException)
                {
                    _logger.LogError(eventId, disconnectException, "Disconnecting from remote Mqtt-Broker failed.");
                }
                finally
                {
                    cancellationTokenSource?.Dispose();
                }

                throw new Exception(errorMessage);
            }
            finally
            {
                cancellationTokenSource?.Dispose();
            }

            #endregion
        }