From 7625bbcb6c6fc04faae2e92ffbb9114e23763f2a Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Mon, 14 May 2018 19:23:00 +1200 Subject: [PATCH] Add HubConnection.State (#2204) --- .../HubConnection.cs | 20 ++++++ .../HubConnectionState.cs | 20 ++++++ .../HubConnectionTests.ConnectionLifecycle.cs | 67 +++++++++++++++++++ 3 files changed, 107 insertions(+) create mode 100644 src/Microsoft.AspNetCore.SignalR.Client.Core/HubConnectionState.cs 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(); + connection.Closed += exception => + { + closed.TrySetResult(null); + Assert.Equal(HubConnectionState.Disconnected, connection.State); + return Task.CompletedTask; + }; + + Assert.Equal(HubConnectionState.Disconnected, connection.State); + + await connection.StartAsync().OrTimeout(); + Assert.True(testConnection.Started.IsCompleted); + Assert.Equal(HubConnectionState.Connected, connection.State); + + await connection.StopAsync().OrTimeout(); + await testConnection.Disposed.OrTimeout(); + Assert.Equal(HubConnectionState.Disconnected, connection.State); + + await closed.Task.OrTimeout(); + }); + } + [Fact] public async Task StopAsyncStopsConnection() { @@ -247,13 +308,18 @@ 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().OrTimeout(); Assert.True(testConnection.Started.IsCompleted); + Assert.Equal(HubConnectionState.Connected, connection.State); await connection.StopAsync().OrTimeout(); await testConnection.Disposed.OrTimeout(); + Assert.Equal(HubConnectionState.Disconnected, connection.State); await connection.StopAsync().OrTimeout(); + Assert.Equal(HubConnectionState.Disconnected, connection.State); }); } @@ -396,6 +462,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests hubConnection.HandshakeTimeout = TimeSpan.FromMilliseconds(1); await Assert.ThrowsAsync(() => hubConnection.StartAsync().OrTimeout()); + Assert.Equal(HubConnectionState.Disconnected, hubConnection.State); } finally {