From 9e635724c00120d0e28be6ae83a76dfe11f06f6c Mon Sep 17 00:00:00 2001
From: Brennan <brecon@microsoft.com>
Date: Thu, 16 Jul 2020 16:46:15 -0700
Subject: [PATCH] StopAsync resets state on inactive connection (#20083)
 (#23962)

---
 .../csharp/Client.Core/src/HubConnection.cs   |  5 +++++
 .../HubConnectionTests.ConnectionLifecycle.cs | 20 +++++++++++++++++++
 2 files changed, 25 insertions(+)

diff --git a/src/SignalR/clients/csharp/Client.Core/src/HubConnection.cs b/src/SignalR/clients/csharp/Client.Core/src/HubConnection.cs
index e8d35d753fc..392d0ac7c8f 100644
--- a/src/SignalR/clients/csharp/Client.Core/src/HubConnection.cs
+++ b/src/SignalR/clients/csharp/Client.Core/src/HubConnection.cs
@@ -501,6 +501,11 @@ namespace Microsoft.AspNetCore.SignalR.Client
                 {
                     connectionState.Stopping = true;
                 }
+                else
+                {
+                    // Reset StopCts if there isn't an active connection so that the next StartAsync wont immediately fail due to the token being canceled
+                    _state.StopCts = new CancellationTokenSource();
+                }
 
                 if (disposing)
                 {
diff --git a/src/SignalR/clients/csharp/Client/test/UnitTests/HubConnectionTests.ConnectionLifecycle.cs b/src/SignalR/clients/csharp/Client/test/UnitTests/HubConnectionTests.ConnectionLifecycle.cs
index 3c669ef94dd..f1d191ee8ca 100644
--- a/src/SignalR/clients/csharp/Client/test/UnitTests/HubConnectionTests.ConnectionLifecycle.cs
+++ b/src/SignalR/clients/csharp/Client/test/UnitTests/HubConnectionTests.ConnectionLifecycle.cs
@@ -334,6 +334,26 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
                 });
             }
 
+            [Fact]
+            public async Task StopAsyncOnInactiveConnectionDoesNotAffectNextStartAsync()
+            {
+                // Regression test:
+                // If there wasn't an active underlying connection, StopAsync would leave a CTS canceled which would cause the next StartAsync to fail
+                var testConnection = new TestConnection();
+                await AsyncUsing(CreateHubConnection(testConnection), async connection =>
+                {
+                    Assert.Equal(HubConnectionState.Disconnected, connection.State);
+
+                    await connection.StopAsync().OrTimeout();
+                    Assert.False(testConnection.Disposed.IsCompleted);
+                    Assert.Equal(HubConnectionState.Disconnected, connection.State);
+
+                    await connection.StartAsync().OrTimeout();
+                    Assert.True(testConnection.Started.IsCompleted);
+                    Assert.Equal(HubConnectionState.Connected, connection.State);
+                });
+            }
+
             [Fact]
             public async Task CompletingTheTransportSideMarksConnectionAsClosed()
             {
-- 
GitLab