diff --git a/src/SignalR/clients/csharp/Client.Core/src/HubConnectionBuilder.cs b/src/SignalR/clients/csharp/Client.Core/src/HubConnectionBuilder.cs index 54b33e572446..b9910ea786c8 100644 --- a/src/SignalR/clients/csharp/Client.Core/src/HubConnectionBuilder.cs +++ b/src/SignalR/clients/csharp/Client.Core/src/HubConnectionBuilder.cs @@ -21,6 +21,22 @@ public class HubConnectionBuilder : IHubConnectionBuilder /// public IServiceCollection Services { get; } + /// + /// Gets or sets the server timeout interval for the connection. + /// + /// + /// The client times out if it hasn't heard from the server for `this` long. + /// + public TimeSpan? ServerTimeout { get; set; } + + /// + /// Gets or sets the interval at which the client sends ping messages. + /// + /// + /// Sending any message resets the timer to the start of the interval. + /// + public TimeSpan? KeepAliveInterval { get; set; } + /// /// Initializes a new instance of the class. /// @@ -52,7 +68,19 @@ public HubConnection Build() var endPoint = serviceProvider.GetService() ?? throw new InvalidOperationException($"Cannot create {nameof(HubConnection)} instance. An {nameof(EndPoint)} was not configured."); - return serviceProvider.GetRequiredService(); + var hubConnection = serviceProvider.GetRequiredService(); + + if (ServerTimeout.HasValue) + { + hubConnection.ServerTimeout = ServerTimeout.Value; + } + + if (KeepAliveInterval.HasValue) + { + hubConnection.KeepAliveInterval = KeepAliveInterval.Value; + } + + return hubConnection; } // Prevents from being displayed in intellisense diff --git a/src/SignalR/clients/csharp/Client.Core/src/PublicAPI.Unshipped.txt b/src/SignalR/clients/csharp/Client.Core/src/PublicAPI.Unshipped.txt index 40077fde5c02..7717d245a8a5 100644 --- a/src/SignalR/clients/csharp/Client.Core/src/PublicAPI.Unshipped.txt +++ b/src/SignalR/clients/csharp/Client.Core/src/PublicAPI.Unshipped.txt @@ -1,4 +1,8 @@ #nullable enable +Microsoft.AspNetCore.SignalR.Client.HubConnectionBuilder.KeepAliveInterval.get -> System.TimeSpan? +Microsoft.AspNetCore.SignalR.Client.HubConnectionBuilder.KeepAliveInterval.set -> void +Microsoft.AspNetCore.SignalR.Client.HubConnectionBuilder.ServerTimeout.get -> System.TimeSpan? +Microsoft.AspNetCore.SignalR.Client.HubConnectionBuilder.ServerTimeout.set -> void static Microsoft.AspNetCore.SignalR.Client.HubConnectionExtensions.On(this Microsoft.AspNetCore.SignalR.Client.HubConnection! hubConnection, string! methodName, System.Func!>! handler) -> System.IDisposable! static Microsoft.AspNetCore.SignalR.Client.HubConnectionExtensions.On(this Microsoft.AspNetCore.SignalR.Client.HubConnection! hubConnection, string! methodName, System.Func! handler) -> System.IDisposable! static Microsoft.AspNetCore.SignalR.Client.HubConnectionExtensions.On(this Microsoft.AspNetCore.SignalR.Client.HubConnection! hubConnection, string! methodName, System.Func!>! handler) -> System.IDisposable! diff --git a/src/SignalR/clients/csharp/Client/test/UnitTests/HubConnectionBuilderTests.cs b/src/SignalR/clients/csharp/Client/test/UnitTests/HubConnectionBuilderTests.cs index f9473ae9a1b5..6bec4935cade 100644 --- a/src/SignalR/clients/csharp/Client/test/UnitTests/HubConnectionBuilderTests.cs +++ b/src/SignalR/clients/csharp/Client/test/UnitTests/HubConnectionBuilderTests.cs @@ -77,4 +77,32 @@ public void AddMessagePackProtocolSetsHubProtocolToMsgPack() Assert.IsType(serviceProvider.GetService()); } + + [Fact] + public void CanSetServerTimeout() + { + var serverTimeout = TimeSpan.FromMinutes(1); + var builder = new HubConnectionBuilder(); + builder.Services.AddSingleton(new HttpConnectionFactory(Options.Create(new HttpConnectionOptions()), NullLoggerFactory.Instance)); + builder.WithUrl("http://example.com"); + builder.ServerTimeout = serverTimeout; + + var connection = builder.Build(); + + Assert.Equal(builder.ServerTimeout, connection.ServerTimeout); + } + + [Fact] + public void CanSetKeepAliveInterval() + { + var keepAliveInterval = TimeSpan.FromMinutes(2); + var builder = new HubConnectionBuilder(); + builder.Services.AddSingleton(new HttpConnectionFactory(Options.Create(new HttpConnectionOptions()), NullLoggerFactory.Instance)); + builder.WithUrl("http://example.com"); + builder.KeepAliveInterval = keepAliveInterval; + + var connection = builder.Build(); + + Assert.Equal(builder.KeepAliveInterval, connection.KeepAliveInterval); + } } diff --git a/src/SignalR/clients/ts/signalr/src/HubConnectionBuilder.ts b/src/SignalR/clients/ts/signalr/src/HubConnectionBuilder.ts index 2cf4e09a3dbf..f21a642bd0c5 100644 --- a/src/SignalR/clients/ts/signalr/src/HubConnectionBuilder.ts +++ b/src/SignalR/clients/ts/signalr/src/HubConnectionBuilder.ts @@ -48,6 +48,22 @@ export class HubConnectionBuilder { /** @internal */ public logger?: ILogger; + /** The server timeout in milliseconds. + * + * If this timeout elapses without receiving any messages from the server, the connection will be terminated with an error. + * The default timeout value is 30,000 milliseconds (30 seconds). + */ + public serverTimeoutInMilliseconds?: number; + + /** Default interval at which to ping the server. + * + * The default value is 15,000 milliseconds (15 seconds). + * Allows the server to detect hard disconnects (like when a client unplugs their computer). + * The ping will happen at most as often as the server pings. + * If the server pings every 5 seconds, a value lower than 5 will ping every 5 seconds. + */ + public keepAliveIntervalInMilliseconds?: number; + /** If defined, this indicates the client should automatically attempt to reconnect if the connection is lost. */ /** @internal */ public reconnectPolicy?: IRetryPolicy; @@ -204,11 +220,21 @@ export class HubConnectionBuilder { } const connection = new HttpConnection(this.url, httpConnectionOptions); - return HubConnection.create( + const hubConnection = HubConnection.create( connection, this.logger || NullLogger.instance, this.protocol || new JsonHubProtocol(), this.reconnectPolicy); + + if (this.serverTimeoutInMilliseconds !== undefined) { + hubConnection.serverTimeoutInMilliseconds = this.serverTimeoutInMilliseconds; + } + + if (this.keepAliveIntervalInMilliseconds !== undefined) { + hubConnection.keepAliveIntervalInMilliseconds = this.keepAliveIntervalInMilliseconds; + } + + return hubConnection; } }