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