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);
}