Skip to content

Expose ConnectionId on .NET Client #8668

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Mar 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public partial class HubConnection
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 { } }
Expand Down
11 changes: 11 additions & 0 deletions src/SignalR/clients/csharp/Client.Core/src/HubConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ public partial class HubConnection
private long _nextActivationSendPing;
private bool _disposed;
private bool _hasInherentKeepAlive;
private string _connectionId;

private CancellationToken _uploadStreamToken;

Expand Down Expand Up @@ -116,6 +117,13 @@ public partial class HubConnection
/// </summary>
public TimeSpan HandshakeTimeout { get; set; } = DefaultHandshakeTimeout;

/// <summary>
/// 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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is incorrect. Negotiate is only skipped when Websockets AND SkipNegotiate are set.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think SkipNegotiate is only possible when Websockets is set. Could simplify the comment to just meantion it.

/// client skips negotiation in that case as well.
/// </summary>
public string ConnectionId => _connectionId;

/// <summary>
/// Indicates the state of the <see cref="HubConnection"/> to the server.
/// </summary>
Expand Down Expand Up @@ -338,6 +346,7 @@ private async Task StartAsyncCore(CancellationToken cancellationToken)

// Start the connection
var connection = await _connectionFactory.ConnectAsync(_protocol.TransferFormat);
_connectionId = connection.ConnectionId;
var startingConnectionState = new ConnectionState(connection, this);
_hasInherentKeepAlive = connection.Features.Get<IConnectionInherentKeepAliveFeature>()?.HasInherentKeepAlive ?? false;

Expand Down Expand Up @@ -405,6 +414,8 @@ private async Task StopAsyncCore(bool disposing)
(_serviceProvider as IDisposable)?.Dispose();
_disposed = true;
}

_connectionId = null;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if we care about this, lets see what other people think

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like nulling it out once the connection is stopped.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stopped or disposed?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stopped. The ConnectionId isn't that useful after you've disconnected, and it can take on multiple values prior to being disposed.

}
finally
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,41 @@ public async Task CanStopAndStartConnection(string protocolName, HttpTransportTy
}
}

[Theory]
[MemberData(nameof(HubProtocolsAndTransportsAndHubPaths))]
[LogLevel(LogLevel.Trace)]
public async Task CanAccessConnectionIdFromHubConnection(string protocolName, HttpTransportType transportType, string path)
{
var protocol = HubProtocols[protocolName];
using (StartServer<Startup>(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<string>(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<string>(nameof(TestHub.GetCallerConnectionId)).OrTimeout();
Assert.NotEqual(originalClientConnectionId, connectionIdFromServer);
Assert.Equal(connection.ConnectionId, connectionIdFromServer);
}
catch (Exception ex)
{
LoggerFactory.CreateLogger<HubConnectionTests>().LogError(ex, "{ExceptionType} from test", ex.GetType().FullName);
throw;
}
finally
{
await connection.DisposeAsync().OrTimeout();
}
}
}

[Theory]
[MemberData(nameof(HubProtocolsAndTransportsAndHubPaths))]
[LogLevel(LogLevel.Trace)]
Expand Down
15 changes: 15 additions & 0 deletions src/SignalR/clients/csharp/Client/test/FunctionalTests/Hubs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ public async Task CallHandlerThatDoesntExist()
await Clients.Client(Context.ConnectionId).SendAsync("NoClientHandler");
}

public string GetCallerConnectionId()
{
return Context.ConnectionId;
}

public ChannelReader<string> StreamEcho(ChannelReader<string> source) => TestHubMethodsImpl.StreamEcho(source);

public string GetUserIdentifier()
Expand Down Expand Up @@ -110,6 +115,11 @@ public async Task CallHandlerThatDoesntExist()
await Clients.Client(Context.ConnectionId).NoClientHandler();
}

public string GetCallerConnectionId()
{
return Context.ConnectionId;
}

public ChannelReader<string> StreamEcho(ChannelReader<string> source) => TestHubMethodsImpl.StreamEcho(source);
}

Expand All @@ -135,6 +145,11 @@ public async Task CallHandlerThatDoesntExist()
await Clients.Client(Context.ConnectionId).NoClientHandler();
}

public string GetCallerConnectionId()
{
return Context.ConnectionId;
}

public ChannelReader<string> StreamEcho(ChannelReader<string> source) => TestHubMethodsImpl.StreamEcho(source);
}

Expand Down