diff --git a/src/Microsoft.AspNetCore.SignalR.Client.Core/HubConnection.cs b/src/Microsoft.AspNetCore.SignalR.Client.Core/HubConnection.cs
index cbdaae61f4..f9d02156aa 100644
--- a/src/Microsoft.AspNetCore.SignalR.Client.Core/HubConnection.cs
+++ b/src/Microsoft.AspNetCore.SignalR.Client.Core/HubConnection.cs
@@ -58,6 +58,24 @@ namespace Microsoft.AspNetCore.SignalR.Client
public TimeSpan ServerTimeout { get; set; } = DefaultServerTimeout;
public TimeSpan HandshakeTimeout { get; set; } = DefaultHandshakeTimeout;
+ ///
+ /// Indicates the state of the to the server.
+ ///
+ public HubConnectionState State
+ {
+ get
+ {
+ // Copy reference for thread-safety
+ var connectionState = _connectionState;
+ if (connectionState == null || connectionState.Stopped)
+ {
+ return HubConnectionState.Disconnected;
+ }
+
+ return HubConnectionState.Connected;
+ }
+ }
+
///
/// Initializes a new instance of the class.
///
@@ -994,6 +1012,8 @@ namespace Microsoft.AspNetCore.SignalR.Client
set => _stopping = value;
}
+ public bool Stopped => _stopTcs?.Task.Status == TaskStatus.RanToCompletion;
+
public ConnectionState(ConnectionContext connection, HubConnection hubConnection)
{
_hubConnection = hubConnection;
diff --git a/src/Microsoft.AspNetCore.SignalR.Client.Core/HubConnectionState.cs b/src/Microsoft.AspNetCore.SignalR.Client.Core/HubConnectionState.cs
new file mode 100644
index 0000000000..279c5a5ffc
--- /dev/null
+++ b/src/Microsoft.AspNetCore.SignalR.Client.Core/HubConnectionState.cs
@@ -0,0 +1,20 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.AspNetCore.SignalR.Client
+{
+ ///
+ /// Describes the current state of the to the server.
+ ///
+ public enum HubConnectionState
+ {
+ ///
+ /// The hub connection is disconnected.
+ ///
+ Disconnected,
+ ///
+ /// The hub connection is open.
+ ///
+ Connected
+ }
+}
\ No newline at end of file
diff --git a/test/Microsoft.AspNetCore.SignalR.Client.Tests/HubConnectionTests.ConnectionLifecycle.cs b/test/Microsoft.AspNetCore.SignalR.Client.Tests/HubConnectionTests.ConnectionLifecycle.cs
index 4bb97308af..ae0ae74cd1 100644
--- a/test/Microsoft.AspNetCore.SignalR.Client.Tests/HubConnectionTests.ConnectionLifecycle.cs
+++ b/test/Microsoft.AspNetCore.SignalR.Client.Tests/HubConnectionTests.ConnectionLifecycle.cs
@@ -55,8 +55,11 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
var testConnection = new TestConnection();
await AsyncUsing(CreateHubConnection(testConnection), async connection =>
{
+ Assert.Equal(HubConnectionState.Disconnected, connection.State);
+
await connection.StartAsync();
Assert.True(testConnection.Started.IsCompleted);
+ Assert.Equal(HubConnectionState.Connected, connection.State);
});
}
@@ -104,12 +107,18 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
await AsyncUsing(CreateHubConnection(ConnectionFactory, DisposeAsync), async connection =>
{
+ Assert.Equal(HubConnectionState.Disconnected, connection.State);
+
await connection.StartAsync().OrTimeout();
Assert.Equal(1, createCount);
+ Assert.Equal(HubConnectionState.Connected, connection.State);
+
await connection.StopAsync().OrTimeout();
+ Assert.Equal(HubConnectionState.Disconnected, connection.State);
await connection.StartAsync().OrTimeout();
Assert.Equal(2, createCount);
+ Assert.Equal(HubConnectionState.Connected, connection.State);
});
}
@@ -216,6 +225,58 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
});
}
+ [Fact]
+ public async Task StatusIsNotConnectedUntilStartAsyncIsFinished()
+ {
+ // Set up StartAsync to wait on the syncPoint when starting
+ var testConnection = new TestConnection(onStart: SyncPoint.Create(out var syncPoint));
+ await AsyncUsing(CreateHubConnection(testConnection), async connection =>
+ {
+ // Start, and wait for the sync point to be hit
+ var startTask = connection.StartAsync().OrTimeout();
+ Assert.False(startTask.IsCompleted);
+ await syncPoint.WaitForSyncPoint();
+
+ Assert.Equal(HubConnectionState.Disconnected, connection.State);
+
+ // Release the SyncPoint
+ syncPoint.Continue();
+
+ // Wait for start to finish
+ await startTask;
+
+ Assert.Equal(HubConnectionState.Connected, connection.State);
+ });
+ }
+
+ [Fact]
+ public async Task StatusIsDisconnectedInCloseEvent()
+ {
+ var testConnection = new TestConnection();
+ await AsyncUsing(CreateHubConnection(testConnection), async connection =>
+ {
+ var closed = new TaskCompletionSource