Unable to connect to MQTTNet server deployed as docker container

  c#, connect, containers, docker, mqttnet

I have a sample MQTTNet server that I want to deploy as a docker container.
Below is the server code which is part of a Net Core Web App (net core 2.2) where I would manually build and deploy to Docker in command line:

I am using net core 2.2, mqttnet 3.0.8.

“docker build -t mqttwebservice .”
“docker run -d -p 32780:80 -p 1883:1883 –name myapp2 mqttwebservice”

The deployment is successful.
However, I could not connect to the MQTT server (MqttCommunicationTimedOutException).

1) What could prevent mqtt client from communicating with the server?

2) How can I know whether the server was started up correctly?

DockerFile

FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
WORKDIR /app
EXPOSE 80
EXPOSE 1883

FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
WORKDIR /src
COPY ["MQTTWebService.csproj", "MQTTWebService/"]
RUN dotnet restore "MQTTWebService/MQTTWebService.csproj"
COPY . .
WORKDIR "/src/MQTTWebService"
COPY . .
RUN dotnet build "MQTTWebService.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "MQTTWebService.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "MQTTWebService.dll"]
namespace MQTTWebService
{
    using System;
    using System.Net;
    using System.Security.Authentication;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    using Microsoft.Extensions.Hosting;
    using Microsoft.Extensions.Logging;
    using MQTTnet;
    using MQTTnet.Server;

    public class MQTTService : BackgroundService
    {
        private static ILogger<MQTTService> mqttServiceLogger;

        private MQTTConfiguration mqttConfiguration;

        private IMqttServerOptions mqttServerOptions;

        private IMqttServer mqttServer;


        /// <summary>
        /// TODO: Implement client connection validator here
        /// </summary>
        private Action<MqttConnectionValidatorContext> MQTTConnectionValidator = (c) =>
        {
            LogMessage(mqttServiceLogger, c);
        };



        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="logger"></param>
        public MQTTService(ILogger<MQTTService> logger)
        {
            mqttServiceLogger = logger;

            this.mqttConfiguration = new MQTTConfiguration
            {
                BrokerHostName = "127.0.0.1",
                BrokerPort = 1883,
                MqttSslProtocol = SslProtocols.None,
                UseSSL = false,
            };
            this.BuildServerOptions();
            this.CreateMqttServer();
        }


        public override async Task StartAsync(CancellationToken cancellationToken)
        {
            await this.StartMqttServerAsync();
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                mqttServiceLogger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
                await Task.Delay(1000, stoppingToken);
            }
        }


        private void BuildServerOptions()
        {
            try
            {
                IPAddress ipAddress = IPAddress.Parse(this.mqttConfiguration.BrokerHostName);
                MqttServerOptionsBuilder optionsBuilder = new MqttServerOptionsBuilder();

                if (this.mqttConfiguration.UseSSL)
                {
                    //// TODO: Implement insert certification
                    optionsBuilder.WithClientCertificate()
                        .WithEncryptionSslProtocol(this.mqttConfiguration.MqttSslProtocol);
                }

                optionsBuilder.WithDefaultEndpointBoundIPAddress(ipAddress)
                    .WithDefaultEndpointPort(this.mqttConfiguration.BrokerPort)
                    .WithConnectionValidator(MQTTConnectionValidator)
                    .WithSubscriptionInterceptor(c =>
                    {
                        c.AcceptSubscription = true;
                        LogMessage(mqttServiceLogger, c, true);
                    })
                    .WithApplicationMessageInterceptor(c =>
                    {
                        c.AcceptPublish = true;
                        LogMessage(mqttServiceLogger, c);
                    });

                this.mqttServerOptions = optionsBuilder.Build();
            }
            catch (Exception ex)
            {
                mqttServiceLogger.LogError(ex.Message);
                throw;
            }
        }

        private void CreateMqttServer()
        {
            try
            {
                this.mqttServer = new MqttFactory().CreateMqttServer();

                //// Add handlers for server
                this.mqttServer.UseClientConnectedHandler(ClientConnectedHandler);
                this.mqttServer.UseClientDisconnectedHandler(ClientDisconnectedHandler);

                this.mqttServer.ClientSubscribedTopicHandler = new MqttServerClientSubscribedHandlerDelegate(args =>
                {
                    try
                    {
                        string clientID = args.ClientId;
                        TopicFilter topicFilter = args.TopicFilter;

                        string topicString = ConvertTopicFilterToString(topicFilter);
                        mqttServiceLogger.LogInformation($"[{DateTime.Now}] Client '{clientID}' subscribed to {topicString}.");
                    }
                    catch (Exception ex)
                    {
                        mqttServiceLogger.LogError(ex.Message);
                    }
                });

                this.mqttServer.ClientUnsubscribedTopicHandler = new MqttServerClientUnsubscribedTopicHandlerDelegate(args =>
                {
                    try
                    {
                        string clientID = args.ClientId;
                        string topicFilter = args.TopicFilter;

                        mqttServiceLogger.LogInformation($"[{DateTime.Now}] Client '{clientID}' un-subscribed to {topicFilter}.");
                    }
                    catch (Exception ex)
                    {
                        mqttServiceLogger.LogError(ex.Message);
                    }
                });
            }
            catch (Exception ex)
            {
                mqttServiceLogger.LogError(ex.Message);
                throw;
            }
        }

        private async Task StartMqttServerAsync()
        {
            try
            {
                if (this.mqttServerOptions == null)
                {
                    throw new ArgumentNullException(nameof(this.mqttServerOptions));
                }

                await this.mqttServer.StartAsync(this.mqttServerOptions);
            }
            catch (Exception ex)
            {
                mqttServiceLogger.LogError(ex.Message);
                throw;
            }
        }



        public static void ClientConnectedHandler(MqttServerClientConnectedEventArgs args)
        {
            try
            {
                string clientID = args.ClientId;
            }
            catch (Exception ex)
            {
                mqttServiceLogger.LogError(ex.Message);
            }
        }

        public static void ClientDisconnectedHandler(MqttServerClientDisconnectedEventArgs args)
        {
            try
            {
                string clientID = args.ClientId;
                MqttClientDisconnectType mqttClientDisconnectType = args.DisconnectType;
            }
            catch (Exception ex)
            {
                mqttServiceLogger.LogError(ex.Message);
            }
        }

        private static string ConvertTopicFilterToString(TopicFilter topicFilter)
        {
            string output = string.Empty;

            if (topicFilter != null)
            {
                output = $"{topicFilter.Topic} - {topicFilter.QualityOfServiceLevel.ToString()}";
            }

            return output;
        }

        /// <summary> 
        /// Logs the message from the MQTT subscription interceptor context. 
        /// </summary> 
        /// <param name="context">The MQTT subscription interceptor context.</param> 
        /// <param name="successful">A <see cref="bool"/> value indicating whether the subscription was successful or not.</param> 
        private static void LogMessage(ILogger<MQTTService> logger, MqttSubscriptionInterceptorContext context, bool successful)
        {
            if (context == null)
            {
                return;
            }

            logger.LogInformation(successful ? $"New subscription: ClientId = {context.ClientId}, TopicFilter = {context.TopicFilter}" : $"Subscription failed for clientId = {context.ClientId}, TopicFilter = {context.TopicFilter}");
        }

        /// <summary>
        /// Logs the message from the MQTT message interceptor context.
        /// </summary>
        /// <param name="context">The MQTT message interceptor context.</param>
        private static void LogMessage(ILogger<MQTTService> logger, MqttApplicationMessageInterceptorContext context)
        {
            if (context == null)
            {
                return;
            }

            var payload = context.ApplicationMessage?.Payload == null ? null : Encoding.UTF8.GetString(context.ApplicationMessage?.Payload);

            logger.LogInformation(
                $"Message: ClientId = {context.ClientId}, Topic = {context.ApplicationMessage?.Topic},"
                + $" Payload = {payload}, QoS = {context.ApplicationMessage?.QualityOfServiceLevel},"
                + $" Retain-Flag = {context.ApplicationMessage?.Retain}");
        }

        /// <summary> 
        /// Logs the message from the MQTT connection validation context. 
        /// </summary> 
        /// <param name="context">The MQTT connection validation context.</param> 
        private static void LogMessage(ILogger<MQTTService> logger, MqttConnectionValidatorContext context)
        {
            if (context == null)
            {
                return;
            }

            logger.LogInformation(
                $"New connection: ClientId = {context.ClientId}, Endpoint = {context.Endpoint},"
                + $" Username = {context.Username}, CleanSession = {context.CleanSession}");
        }
    }


    internal class MQTTConfiguration
    {
        public string BrokerHostName { get; set; }
        public bool UseSSL { get; set; }
        public SslProtocols MqttSslProtocol { get; set; }
        public int BrokerPort { get; set; } = 1883;
    }
}

Source: StackOverflow

LEAVE A COMMENT