MQTTnet icon indicating copy to clipboard operation
MQTTnet copied to clipboard

Managed client cannot send topic alias alone (without topic)

Open TheKenny2303 opened this issue 2 years ago • 0 comments

Describe the bug

I want to use the topic alias feature with the managed MQTT client. I can set the alias but it sends always topic and alias. If I keep the topic empty it throws. But the same advance works with the normal client. I have seen that client and managed client use different methods for topic validation. I have checked the packet size with Wireshark to see if there is any benefit to the feature. Is this currently not supported? Have I done something wrong? Is this feature included in a coming version?

Thanks for your work!

Which component is your bug related to?

  • ManagedClient

To Reproduce

Steps to reproduce the behavior:

  1. Using this version of MQTTnet '3.1.2'.
  2. Run the example code
  3. Check the packet and its size.

Expected behavior

I expect to be able to publish the second time without the topic. Or the managed client additionally takes care of using topic aliases itself.

Screenshots

As in my example the frist two messages are from the managed client. The second two from an normal client that is working. With the normal client you can see that the feature works but not with the managed client. image

Additional context / logging

This is the log of my example app.

info: MQTT managed client[0]
      Started
dbug: MQTT managed client[0]
      Trying to connect with server 'localhost:1883' (Timeout=00:00:10).
dbug: MQTT managed client[0]
      Connection with server established.
dbug: MQTT managed client[0]
      Start receiving packets.
dbug: MQTT managed client[0]
      Authenticated MQTT connection with server established.
info: MQTT managed client[0]
      Connected.
info: MQTT managed client[0]
      Publishing subscriptions at reconnect
dbug: MQTT managed client[0]
      Start sending keep alive packets.
dbug: MQTT client[0]
      Trying to connect with server 'localhost:1883' (Timeout=00:00:10).
dbug: MQTT client[0]
      Connection with server established.
dbug: MQTT client[0]
      Start receiving packets.
dbug: MQTT client[0]
      Authenticated MQTT connection with server established.
info: MQTT client[0]
      Connected.
dbug: MQTT client[0]
      Start sending keep alive packets.
dbug: MQTT client[0]
      Stopped sending keep alive packets.
dbug: MQTT managed client[0]
      Stopped sending keep alive packets.
dbug: MQTT managed client[0]
      Disconnecting [Timeout=00:00:10]
dbug: MQTT client[0]
      Stopped receiving packets.
dbug: MQTT managed client[0]
      Disconnected from adapter.
dbug: MQTT managed client[0]
      Stopped publishing messages.
info: MQTT managed client[0]
      Disconnected.
dbug: MQTT managed client[0]
      Stopped receiving packets.

Code example

using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Console;
using Microsoft.Extensions.Options;
using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Client.Options;
using MQTTnet.Diagnostics.Logger;
using MQTTnet.Extensions.ManagedClient;

using var loggingProvider = CreateLoggingProvider();

// ##################################################
// ManagedClient

using var managedClient = CreateManagedMqttClient(loggingProvider.CreateLogger("MQTT managed client"));
{
    await managedClient.PublishAsync(new MqttApplicationMessageBuilder()
        .WithTopic("testAlias")
        .WithTopicAlias(1)
        .Build());

    await managedClient.PublishAsync(new MqttApplicationMessageBuilder()
        .WithTopic("testAlias") // throws without topic
        .WithTopicAlias(1)
        .Build());

    while (managedClient.PendingApplicationMessagesCount > 0)
        await Task.Delay(1);
}

// ##################################################
// Client

using var client = await CreateMqttClientAsync(loggingProvider.CreateLogger("MQTT client"));
{
    await client.PublishAsync(new MqttApplicationMessageBuilder()
        .WithTopic("testAlias")
        .WithTopicAlias(1)
        .Build());

    await client.PublishAsync(new MqttApplicationMessageBuilder()
        .WithTopic("")
        .WithTopicAlias(1)
        .Build());
}

static IManagedMqttClient CreateManagedMqttClient(ILogger logger)
{
    var managedClientOptions = new ManagedMqttClientOptionsBuilder()
        .WithClientOptions(new MqttClientOptionsBuilder()
            .WithClientId("test")
            .WithProtocolVersion(MQTTnet.Formatter.MqttProtocolVersion.V500)
            .WithTcpServer("localhost", 1883)
            .Build())
        .Build();
    var managedClient = new MqttFactory().CreateManagedMqttClient(new MqttMicrosoftLogger(logger));
    managedClient.StartAsync(managedClientOptions);

    return managedClient;
}

static async Task<IMqttClient> CreateMqttClientAsync(ILogger logger)
{
    var clientOptions = new MqttClientOptionsBuilder()
            .WithClientId("test")
            .WithProtocolVersion(MQTTnet.Formatter.MqttProtocolVersion.V500)
            .WithTcpServer("localhost", 1883)
            .Build();
    var client = new MqttFactory().CreateMqttClient(new MqttMicrosoftLogger(logger));
    await client.ConnectAsync(clientOptions);

    return client;
}

static ILoggerProvider CreateLoggingProvider()
    => new ConsoleLoggerProvider(new OptionsMonitor<ConsoleLoggerOptions>(
        new OptionsFactory<ConsoleLoggerOptions>(Enumerable.Empty<IConfigureOptions<ConsoleLoggerOptions>>(), Enumerable.Empty<IPostConfigureOptions<ConsoleLoggerOptions>>()),
        Enumerable.Empty<IOptionsChangeTokenSource<ConsoleLoggerOptions>>(),
        new OptionsCache<ConsoleLoggerOptions>()));

internal class MqttMicrosoftLogger : IMqttNetLogger
{
    private readonly ILogger _logger;

    internal MqttMicrosoftLogger(ILogger logger) => _logger = logger;

    public bool IsEnabled => true;

    public void Publish(MqttNetLogLevel logLevel, string source, string message, object[] parameters, Exception exception)
    {
        var coreLogLevel = logLevel switch
        {
            MqttNetLogLevel.Error => LogLevel.Error,
            MqttNetLogLevel.Info => LogLevel.Information,
            MqttNetLogLevel.Verbose => LogLevel.Debug,
            MqttNetLogLevel.Warning => LogLevel.Warning,
            _ => LogLevel.Trace,
        };
        _logger.Log(coreLogLevel, exception, message, parameters);
    }
}

TheKenny2303 avatar Apr 22 '22 13:04 TheKenny2303