Commit bb9dbda3 authored by Andreas Müller's avatar Andreas Müller

Fixed some issues using Dispose() after Disconnect() and while reconnecting.

parent 249db101
Pipeline #31 passed with stage
in 43 seconds
......@@ -170,33 +170,9 @@ namespace AMWD.Modbus.Tcp.Client
/// Disconnects the client.
/// </summary>
/// <returns>An awaitable task.</returns>
public Task Disconnect()
public async Task Disconnect()
{
if (isDisposed)
{
throw new ObjectDisposedException(GetType().FullName);
}
if (!isStarted)
{
return Task.CompletedTask;
}
bool wasConnected = IsConnected;
reconnectTcs?.TrySetResult(false);
mainCts?.Cancel();
reconnectTcs = null;
tcpClient?.Close();
tcpClient?.Dispose();
tcpClient = null;
if (wasConnected)
{
Task.Run(() => Disconnected?.Invoke(this, EventArgs.Empty)).Forget();
}
return Task.CompletedTask;
await DisconnectInternal(false);
}
#endregion Control
......@@ -1051,6 +1027,11 @@ namespace AMWD.Modbus.Tcp.Client
if (!IsConnected)
{
if (!isReconnecting)
{
Task.Run(() => Reconnect(mainCts.Token)).Forget();
ConnectingTask = GetWaitTask(mainCts.Token);
}
throw new InvalidOperationException("Client is not connected");
}
......@@ -1125,7 +1106,7 @@ namespace AMWD.Modbus.Tcp.Client
tcpClient = new TcpClient(AddressFamily.InterNetworkV6);
tcpClient.Client.DualMode = true;
var task = tcpClient.ConnectAsync(Host, Port);
if (await Task.WhenAny(task, Task.Delay(TimeSpan.FromSeconds(timeout), ct)) == task)
if (await Task.WhenAny(task, Task.Delay(TimeSpan.FromSeconds(timeout), ct)) == task && tcpClient?.Connected == true)
{
logger?.LogInformation("ModbusClient.Reconnect connected");
Task.Run(() => Connected?.Invoke(this, EventArgs.Empty)).Forget();
......@@ -1183,6 +1164,46 @@ namespace AMWD.Modbus.Tcp.Client
}
}
private async Task DisconnectInternal(bool disposing)
{
if (isDisposed && !disposing)
{
throw new ObjectDisposedException(GetType().FullName);
}
if (!isStarted)
{
return;
}
isStarted = false;
bool wasConnected = IsConnected;
try
{
reconnectTcs?.TrySetResult(false);
mainCts?.Cancel();
reconnectTcs = null;
}
catch
{ }
try
{
tcpClient?.Close();
tcpClient?.Dispose();
tcpClient = null;
}
catch
{ }
if (wasConnected)
{
Task.Run(() => Disconnected?.Invoke(this, EventArgs.Empty)).Forget();
}
await Task.CompletedTask;
}
#endregion Private Methods
#region IDisposable implementation
......@@ -1204,9 +1225,11 @@ namespace AMWD.Modbus.Tcp.Client
{
return;
}
Disconnect().GetAwaiter().GetResult();
isDisposed = true;
DisconnectInternal(true)
.GetAwaiter()
.GetResult();
}
#endregion IDisposable implementation
......
......@@ -49,18 +49,15 @@ namespace UnitTests
using (var client = new ModbusClient(IPAddress.Loopback, server.Port))
{
await client.Connect();
await EnsureWait();
Assert.IsTrue(client.IsConnected);
await server.Stop();
await client.ReadHoldingRegisters(0, 0, 1);
await EnsureWait();
Assert.IsFalse(client.IsConnected);
server.Start();
await client.ConnectingTask;
await EnsureWait();
Assert.IsTrue(client.IsConnected);
}
}
......@@ -91,17 +88,16 @@ namespace UnitTests
await client.Connect();
Assert.IsTrue(client.IsConnected);
await EnsureWait();
await EnsureWait(); // get events raised
Assert.AreEqual(1, connectEvents);
Assert.AreEqual(0, disconnectEvents);
await server.Stop();
await client.ReadHoldingRegisters(0, 0, 1);
await EnsureWait();
Assert.IsFalse(client.IsConnected);
await EnsureWait();
await EnsureWait(); // get events raised
Assert.AreEqual(1, connectEvents);
Assert.AreEqual(1, disconnectEvents);
......@@ -110,7 +106,7 @@ namespace UnitTests
Assert.IsTrue(client.IsConnected);
}
await EnsureWait();
await EnsureWait(); // get events raised
Assert.AreEqual(2, connectEvents);
Assert.AreEqual(2, disconnectEvents);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment