dotnet / MQTTnet

MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker). The implementation is based on the documentation from http://mqtt.org/.
MIT License
4.51k stars 1.07k forks source link

Sporadic "MqttCommunicationException: Cannot access a disposed object" on MqttClient.DisconnectAsync() #728

Closed ps-weber closed 4 years ago

ps-weber commented 5 years ago

.NET Version: Framework 4.7.2 MQTTnet nuget Version: 3.0.5

I have a sporadically occurring problem when calling the Method IMqttClient.DisconnectAsync(). The messages are transmitted over unencrypted TCP.

The MQTT server is a Mosquitto 1.6.3. The log messages just say that the client has disconnected, as expected.

My Code is roughly:

IMqttClient _mqttClient;

void Init()
{
    var factory = new MqttFactory();
    _mqttClient = factory.CreateMqttClient();
}

async Task SendMessage(MqttApplicationMessage message)
{
    try
    {
    await _mqttClient.ConnectAsync(options);
    await _mqttClient.PublishAsync(message);
    }
    finally
    {
        await _mqttClient.DisconnectAsync();
    }
}

I get the following stacktrace:

    MqttCommunicationException: Cannot access a disposed object.
    Object name: 'System.Net.Sockets.NetworkStream'.
    --------------------------------------------------------------------------------
    *** Stacktrace ***
       at MQTTnet.Adapter.MqttChannelAdapter.WrapException(Exception exception)
       at MQTTnet.Adapter.MqttChannelAdapter.<SendPacketAsync>d__34.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at MQTTnet.Client.MqttClient.<DisconnectAsync>d__34.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
       at MQTTnet.Client.MqttClient.<DisconnectAsync>d__34.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)

       ... My Code ...

    --------------------------------------------------------------------------------
    *** Inner Exception ***
        ObjectDisposedException: Cannot access a disposed object.
        Object name: 'System.Net.Sockets.NetworkStream'.
        ----------------------------------------------------------------------------
        *** Stacktrace ***
           at System.Net.Sockets.NetworkStream.EndWrite(IAsyncResult asyncResult)
           at System.IO.Stream.<>c.<BeginEndWriteAsync>b__53_1(Stream stream, IAsyncResult asyncResult)
           at System.Threading.Tasks.TaskFactory`1.FromAsyncTrimPromise`1.Complete(TInstance thisRef, Func`3 endMethod, IAsyncResult asyncResult, Boolean requiresSynchronization)
        --- End of stack trace from previous location where exception was thrown ---
           at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
           at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
           at MQTTnet.Implementations.MqttTcpChannel.<WriteAsync>d__18.MoveNext()
        --- End of stack trace from previous location where exception was thrown ---
           at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
           at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
           at MQTTnet.Internal.MqttTaskTimeout.<WaitAsync>d__0.MoveNext()
        --- End of stack trace from previous location where exception was thrown ---
           at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
           at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
SeppPenner commented 5 years ago
void SendMessage(MqttApplicationMessage message)
{
    try
    {
    await _mqttClient.ConnectAsync(options);
    await _mqttClient.PublishAsync(message);
    }
    finally
    {
        await _mqttClient.DisconnectAsync();
    }
}

This code will not work. You're not awaiting the Tasks because your SendMessage method is synchronous...

ps-weber commented 5 years ago

Sorry, I forgot to add the "async Task" when trying to come up with a minimal example. I edited the issue to match my actual code.

ps-weber commented 5 years ago

Some additional info:

I can only reproduce this behaviour on a specific server. The exception only gets thrown after the first message is sent. Any further messages I send do not generate this exception on DisconnectAsync.

I used the mosquitto tools mosquitto_sub and mosquitto_pub to test the connection to the broker and could not see any irregularities. The broker (mosquitto) is on another server and uses a custom port.

For now, I just ignore any MqttCommunicationException that gets thrown on DisconnectAsync.

SeppPenner commented 5 years ago

Strange... This needs further investigation.

billqian commented 4 years ago

the same issue.

the same code, runs well on the windows 10, failed on raspi 3B.

mqtt server:Mosquitto

SeppPenner commented 4 years ago

@JanEggers This should be fixed in the latest version, I assume?

JanEggers commented 4 years ago

@SeppPenner yes this was fixed with #833