From 017f409fe4f37d4ed8f5e39e581afaa6bd429863 Mon Sep 17 00:00:00 2001 From: Mikael Mengistu Date: Wed, 27 Mar 2019 17:30:43 -0700 Subject: [PATCH] Expose ConnectionId on .NET Client (#8668) --- ...Core.SignalR.Client.Core.netstandard2.0.cs | 1 + .../csharp/Client.Core/src/HubConnection.cs | 11 ++++++ .../FunctionalTests/HubConnectionTests.cs | 35 +++++++++++++++++++ .../Client/test/FunctionalTests/Hubs.cs | 15 ++++++++ 4 files changed, 62 insertions(+) diff --git a/src/SignalR/clients/csharp/Client.Core/ref/Microsoft.AspNetCore.SignalR.Client.Core.netstandard2.0.cs b/src/SignalR/clients/csharp/Client.Core/ref/Microsoft.AspNetCore.SignalR.Client.Core.netstandard2.0.cs index 3c9a824b2b..84c7df7344 100644 --- a/src/SignalR/clients/csharp/Client.Core/ref/Microsoft.AspNetCore.SignalR.Client.Core.netstandard2.0.cs +++ b/src/SignalR/clients/csharp/Client.Core/ref/Microsoft.AspNetCore.SignalR.Client.Core.netstandard2.0.cs @@ -26,6 +26,7 @@ namespace Microsoft.AspNetCore.SignalR.Client public static readonly System.TimeSpan DefaultServerTimeout; public HubConnection(Microsoft.AspNetCore.SignalR.Client.IConnectionFactory connectionFactory, Microsoft.AspNetCore.SignalR.Protocol.IHubProtocol protocol, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) { } public HubConnection(Microsoft.AspNetCore.SignalR.Client.IConnectionFactory connectionFactory, Microsoft.AspNetCore.SignalR.Protocol.IHubProtocol protocol, System.IServiceProvider serviceProvider, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) { } + public string ConnectionId { get { throw null; } } public System.TimeSpan HandshakeTimeout { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } public System.TimeSpan KeepAliveInterval { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } public System.TimeSpan ServerTimeout { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } } diff --git a/src/SignalR/clients/csharp/Client.Core/src/HubConnection.cs b/src/SignalR/clients/csharp/Client.Core/src/HubConnection.cs index e1f20238d0..7807107d77 100644 --- a/src/SignalR/clients/csharp/Client.Core/src/HubConnection.cs +++ b/src/SignalR/clients/csharp/Client.Core/src/HubConnection.cs @@ -54,6 +54,7 @@ namespace Microsoft.AspNetCore.SignalR.Client private long _nextActivationSendPing; private bool _disposed; private bool _hasInherentKeepAlive; + private string _connectionId; private CancellationToken _uploadStreamToken; @@ -123,6 +124,13 @@ namespace Microsoft.AspNetCore.SignalR.Client /// public TimeSpan HandshakeTimeout { get; set; } = DefaultHandshakeTimeout; + /// + /// Gets the connection's current Id. This value will be cleared when the connection is stopped and will have a new value every time the connection is (re)established. + /// This value will be null if the negotiation step is skipped via HttpConnectionOptions or if the WebSockets transport is explicitly specified because the + /// client skips negotiation in that case as well. + /// + public string ConnectionId => _connectionId; + /// /// Indicates the state of the to the server. /// @@ -345,6 +353,7 @@ namespace Microsoft.AspNetCore.SignalR.Client // Start the connection var connection = await _connectionFactory.ConnectAsync(_protocol.TransferFormat); + _connectionId = connection.ConnectionId; var startingConnectionState = new ConnectionState(connection, this); _hasInherentKeepAlive = connection.Features.Get()?.HasInherentKeepAlive ?? false; @@ -412,6 +421,8 @@ namespace Microsoft.AspNetCore.SignalR.Client (_serviceProvider as IDisposable)?.Dispose(); _disposed = true; } + + _connectionId = null; } finally { diff --git a/src/SignalR/clients/csharp/Client/test/FunctionalTests/HubConnectionTests.cs b/src/SignalR/clients/csharp/Client/test/FunctionalTests/HubConnectionTests.cs index 1d403d4609..9ffe7b3eb9 100644 --- a/src/SignalR/clients/csharp/Client/test/FunctionalTests/HubConnectionTests.cs +++ b/src/SignalR/clients/csharp/Client/test/FunctionalTests/HubConnectionTests.cs @@ -155,6 +155,41 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests } } + [Theory] + [MemberData(nameof(HubProtocolsAndTransportsAndHubPaths))] + [LogLevel(LogLevel.Trace)] + public async Task CanAccessConnectionIdFromHubConnection(string protocolName, HttpTransportType transportType, string path) + { + var protocol = HubProtocols[protocolName]; + using (StartServer(out var server)) + { + var connection = CreateHubConnection(server.Url, path, transportType, protocol, LoggerFactory); + try + { + Assert.Null(connection.ConnectionId); + await connection.StartAsync().OrTimeout(); + var originalClientConnectionId = connection.ConnectionId; + var connectionIdFromServer = await connection.InvokeAsync(nameof(TestHub.GetCallerConnectionId)).OrTimeout(); + Assert.Equal(connection.ConnectionId, connectionIdFromServer); + await connection.StopAsync().OrTimeout(); + Assert.Null(connection.ConnectionId); + await connection.StartAsync().OrTimeout(); + connectionIdFromServer = await connection.InvokeAsync(nameof(TestHub.GetCallerConnectionId)).OrTimeout(); + Assert.NotEqual(originalClientConnectionId, connectionIdFromServer); + Assert.Equal(connection.ConnectionId, connectionIdFromServer); + } + catch (Exception ex) + { + LoggerFactory.CreateLogger().LogError(ex, "{ExceptionType} from test", ex.GetType().FullName); + throw; + } + finally + { + await connection.DisposeAsync().OrTimeout(); + } + } + } + [Theory] [MemberData(nameof(HubProtocolsAndTransportsAndHubPaths))] [LogLevel(LogLevel.Trace)] diff --git a/src/SignalR/clients/csharp/Client/test/FunctionalTests/Hubs.cs b/src/SignalR/clients/csharp/Client/test/FunctionalTests/Hubs.cs index af321348b5..53efb39162 100644 --- a/src/SignalR/clients/csharp/Client/test/FunctionalTests/Hubs.cs +++ b/src/SignalR/clients/csharp/Client/test/FunctionalTests/Hubs.cs @@ -36,6 +36,11 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests await Clients.Client(Context.ConnectionId).SendAsync("NoClientHandler"); } + public string GetCallerConnectionId() + { + return Context.ConnectionId; + } + public ChannelReader StreamEcho(ChannelReader source) => TestHubMethodsImpl.StreamEcho(source); public string GetUserIdentifier() @@ -110,6 +115,11 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests await Clients.Client(Context.ConnectionId).NoClientHandler(); } + public string GetCallerConnectionId() + { + return Context.ConnectionId; + } + public ChannelReader StreamEcho(ChannelReader source) => TestHubMethodsImpl.StreamEcho(source); } @@ -135,6 +145,11 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests await Clients.Client(Context.ConnectionId).NoClientHandler(); } + public string GetCallerConnectionId() + { + return Context.ConnectionId; + } + public ChannelReader StreamEcho(ChannelReader source) => TestHubMethodsImpl.StreamEcho(source); }