diff --git a/src/SignalR/clients/csharp/Client.Core/src/HubConnection.cs b/src/SignalR/clients/csharp/Client.Core/src/HubConnection.cs
index f4bc0bb96526..4af2f9c92908 100644
--- a/src/SignalR/clients/csharp/Client.Core/src/HubConnection.cs
+++ b/src/SignalR/clients/csharp/Client.Core/src/HubConnection.cs
@@ -22,8 +22,10 @@
using Microsoft.AspNetCore.SignalR.Client.Internal;
using Microsoft.AspNetCore.SignalR.Internal;
using Microsoft.AspNetCore.SignalR.Protocol;
+using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
+using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.SignalR.Client;
@@ -152,7 +154,7 @@ public partial class HubConnection : IAsyncDisposable
///
/// The client times out if it hasn't heard from the server for `this` long.
///
- public TimeSpan ServerTimeout { get; set; } = DefaultServerTimeout;
+ public TimeSpan ServerTimeout { get; set; }
///
/// Gets or sets the interval at which the client sends ping messages.
@@ -160,7 +162,7 @@ public partial class HubConnection : IAsyncDisposable
///
/// Sending any message resets the timer to the start of the interval.
///
- public TimeSpan KeepAliveInterval { get; set; } = DefaultKeepAliveInterval;
+ public TimeSpan KeepAliveInterval { get; set; }
///
/// Gets or sets the timeout for the initial handshake.
@@ -227,6 +229,12 @@ public HubConnection(IConnectionFactory connectionFactory,
_state = new ReconnectingConnectionState(_logger);
_logScope = new ConnectionLogScope();
+
+ var options = serviceProvider.GetService>();
+
+ ServerTimeout = options?.Value.ServerTimeout ?? DefaultServerTimeout;
+
+ KeepAliveInterval = options?.Value.KeepAliveInterval ?? DefaultKeepAliveInterval;
}
///
diff --git a/src/SignalR/clients/csharp/Client.Core/src/HubConnectionBuilderExtensions.cs b/src/SignalR/clients/csharp/Client.Core/src/HubConnectionBuilderExtensions.cs
index 5979127fa4e4..6dbd4fd98e22 100644
--- a/src/SignalR/clients/csharp/Client.Core/src/HubConnectionBuilderExtensions.cs
+++ b/src/SignalR/clients/csharp/Client.Core/src/HubConnectionBuilderExtensions.cs
@@ -63,4 +63,28 @@ public static IHubConnectionBuilder WithAutomaticReconnect(this IHubConnectionBu
hubConnectionBuilder.Services.AddSingleton(retryPolicy);
return hubConnectionBuilder;
}
+
+ ///
+ /// Configures ServerTimeout for the .
+ ///
+ /// The to configure.
+ /// ServerTimeout for the .
+ /// The same instance of the for chaining.
+ public static IHubConnectionBuilder WithServerTimeout(this IHubConnectionBuilder hubConnectionBuilder, TimeSpan timeout)
+ {
+ hubConnectionBuilder.Services.Configure(o => o.ServerTimeout = timeout);
+ return hubConnectionBuilder;
+ }
+
+ ///
+ /// Configures KeepAliveInterval for the .
+ ///
+ /// The to configure.
+ /// KeepAliveInterval for the .
+ /// The same instance of the for chaining.
+ public static IHubConnectionBuilder WithKeepAliveInterval(this IHubConnectionBuilder hubConnectionBuilder, TimeSpan interval)
+ {
+ hubConnectionBuilder.Services.Configure(o => o.KeepAliveInterval = interval);
+ return hubConnectionBuilder;
+ }
}
diff --git a/src/SignalR/clients/csharp/Client.Core/src/HubConnectionOptions.cs b/src/SignalR/clients/csharp/Client.Core/src/HubConnectionOptions.cs
new file mode 100644
index 000000000000..5ebae3958898
--- /dev/null
+++ b/src/SignalR/clients/csharp/Client.Core/src/HubConnectionOptions.cs
@@ -0,0 +1,26 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Microsoft.AspNetCore.SignalR.Client;
+
+///
+/// Configures timeouts for the .
+///
+internal sealed class HubConnectionOptions
+{
+ ///
+ /// Configures ServerTimeout for the .
+ ///
+ public TimeSpan? ServerTimeout { get; set; }
+
+ ///
+ /// Configures KeepAliveInterval for the .
+ ///
+ public TimeSpan? KeepAliveInterval { get; set; }
+}
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 7dc5c58110bf..a9937988d626 100644
--- a/src/SignalR/clients/csharp/Client.Core/src/PublicAPI.Unshipped.txt
+++ b/src/SignalR/clients/csharp/Client.Core/src/PublicAPI.Unshipped.txt
@@ -1 +1,3 @@
#nullable enable
+static Microsoft.AspNetCore.SignalR.Client.HubConnectionBuilderExtensions.WithKeepAliveInterval(this Microsoft.AspNetCore.SignalR.Client.IHubConnectionBuilder! hubConnectionBuilder, System.TimeSpan interval) -> Microsoft.AspNetCore.SignalR.Client.IHubConnectionBuilder!
+static Microsoft.AspNetCore.SignalR.Client.HubConnectionBuilderExtensions.WithServerTimeout(this Microsoft.AspNetCore.SignalR.Client.IHubConnectionBuilder! hubConnectionBuilder, System.TimeSpan timeout) -> Microsoft.AspNetCore.SignalR.Client.IHubConnectionBuilder!
diff --git a/src/SignalR/clients/csharp/Client/test/UnitTests/HubConnectionBuilderTests.cs b/src/SignalR/clients/csharp/Client/test/UnitTests/HubConnectionBuilderTests.cs
index f9473ae9a1b5..cb0938bf5720 100644
--- a/src/SignalR/clients/csharp/Client/test/UnitTests/HubConnectionBuilderTests.cs
+++ b/src/SignalR/clients/csharp/Client/test/UnitTests/HubConnectionBuilderTests.cs
@@ -77,4 +77,46 @@ public void AddMessagePackProtocolSetsHubProtocolToMsgPack()
Assert.IsType(serviceProvider.GetService());
}
+
+ [Fact]
+ public void CanConfigureServerTimeout()
+ {
+ var serverTimeout = TimeSpan.FromMinutes(1);
+ var builder = new HubConnectionBuilder();
+ builder.WithUrl("http://example.com")
+ .WithServerTimeout(serverTimeout);
+
+ var connection = builder.Build();
+
+ Assert.Equal(serverTimeout, connection.ServerTimeout);
+ }
+
+ [Fact]
+ public void CanConfigureKeepAliveInterval()
+ {
+ var keepAliveInterval = TimeSpan.FromMinutes(1);
+ var builder = new HubConnectionBuilder();
+ builder.WithUrl("http://example.com")
+ .WithKeepAliveInterval(keepAliveInterval);
+
+ var connection = builder.Build();
+
+ Assert.Equal(keepAliveInterval, connection.KeepAliveInterval);
+ }
+
+ [Fact]
+ public void CanConfigureServerTimeoutAndKeepAliveInterval()
+ {
+ var serverTimeout = TimeSpan.FromMinutes(2);
+ var keepAliveInterval = TimeSpan.FromMinutes(3);
+ var builder = new HubConnectionBuilder();
+ builder.WithUrl("http://example.com")
+ .WithServerTimeout(serverTimeout)
+ .WithKeepAliveInterval(keepAliveInterval);
+
+ var connection = builder.Build();
+
+ Assert.Equal(serverTimeout, connection.ServerTimeout);
+ Assert.Equal(keepAliveInterval, connection.KeepAliveInterval);
+ }
}
diff --git a/src/SignalR/clients/ts/signalr/src/HubConnection.ts b/src/SignalR/clients/ts/signalr/src/HubConnection.ts
index b257ec5eafa9..ef17a3ccfa07 100644
--- a/src/SignalR/clients/ts/signalr/src/HubConnection.ts
+++ b/src/SignalR/clients/ts/signalr/src/HubConnection.ts
@@ -92,17 +92,29 @@ export class HubConnection {
// create method that can be used by HubConnectionBuilder. An "internal" constructor would just
// be stripped away and the '.d.ts' file would have no constructor, which is interpreted as a
// public parameter-less constructor.
- public static create(connection: IConnection, logger: ILogger, protocol: IHubProtocol, reconnectPolicy?: IRetryPolicy): HubConnection {
- return new HubConnection(connection, logger, protocol, reconnectPolicy);
+ public static create(
+ connection: IConnection,
+ logger: ILogger,
+ protocol: IHubProtocol,
+ reconnectPolicy?: IRetryPolicy,
+ serverTimeoutInMilliseconds?: number,
+ keepAliveIntervalInMilliseconds?: number): HubConnection {
+ return new HubConnection(connection, logger, protocol, reconnectPolicy, serverTimeoutInMilliseconds, keepAliveIntervalInMilliseconds);
}
- private constructor(connection: IConnection, logger: ILogger, protocol: IHubProtocol, reconnectPolicy?: IRetryPolicy) {
+ private constructor(
+ connection: IConnection,
+ logger: ILogger,
+ protocol: IHubProtocol,
+ reconnectPolicy?: IRetryPolicy,
+ serverTimeoutInMilliseconds?: number,
+ keepAliveIntervalInMilliseconds?: number) {
Arg.isRequired(connection, "connection");
Arg.isRequired(logger, "logger");
Arg.isRequired(protocol, "protocol");
- this.serverTimeoutInMilliseconds = DEFAULT_TIMEOUT_IN_MS;
- this.keepAliveIntervalInMilliseconds = DEFAULT_PING_INTERVAL_IN_MS;
+ this.serverTimeoutInMilliseconds = serverTimeoutInMilliseconds ?? DEFAULT_TIMEOUT_IN_MS;
+ this.keepAliveIntervalInMilliseconds = keepAliveIntervalInMilliseconds ?? DEFAULT_PING_INTERVAL_IN_MS;
this._logger = logger;
this._protocol = protocol;
diff --git a/src/SignalR/clients/ts/signalr/src/HubConnectionBuilder.ts b/src/SignalR/clients/ts/signalr/src/HubConnectionBuilder.ts
index 2cf4e09a3dbf..8cd9c1361440 100644
--- a/src/SignalR/clients/ts/signalr/src/HubConnectionBuilder.ts
+++ b/src/SignalR/clients/ts/signalr/src/HubConnectionBuilder.ts
@@ -39,6 +39,9 @@ function parseLogLevel(name: string): LogLevel {
/** A builder for configuring {@link @microsoft/signalr.HubConnection} instances. */
export class HubConnectionBuilder {
+ private _serverTimeoutInMilliseconds?: number;
+ private _keepAliveIntervalInMilliseconds ?: number;
+
/** @internal */
public protocol?: IHubProtocol;
/** @internal */
@@ -183,6 +186,30 @@ export class HubConnectionBuilder {
return this;
}
+ /** Configures {@link @microsoft/signalr.HubConnection.serverTimeoutInMilliseconds} for the {@link @microsoft/signalr.HubConnection}.
+ *
+ * @returns The {@link @microsoft/signalr.HubConnectionBuilder} instance, for chaining.
+ */
+ public withServerTimeout(milliseconds: number): HubConnectionBuilder {
+ Arg.isRequired(milliseconds, "milliseconds");
+
+ this._serverTimeoutInMilliseconds = milliseconds;
+
+ return this;
+ }
+
+ /** Configures {@link @microsoft/signalr.HubConnection.keepAliveIntervalInMilliseconds} for the {@link @microsoft/signalr.HubConnection}.
+ *
+ * @returns The {@link @microsoft/signalr.HubConnectionBuilder} instance, for chaining.
+ */
+ public withKeepAliveInterval(milliseconds: number): HubConnectionBuilder {
+ Arg.isRequired(milliseconds, "milliseconds");
+
+ this._keepAliveIntervalInMilliseconds = milliseconds;
+
+ return this;
+ }
+
/** Creates a {@link @microsoft/signalr.HubConnection} from the configuration options specified in this builder.
*
* @returns {HubConnection} The configured {@link @microsoft/signalr.HubConnection}.
@@ -208,7 +235,9 @@ export class HubConnectionBuilder {
connection,
this.logger || NullLogger.instance,
this.protocol || new JsonHubProtocol(),
- this.reconnectPolicy);
+ this.reconnectPolicy,
+ this._serverTimeoutInMilliseconds,
+ this._keepAliveIntervalInMilliseconds);
}
}
diff --git a/src/SignalR/clients/ts/signalr/tests/HubConnectionBuilder.test.ts b/src/SignalR/clients/ts/signalr/tests/HubConnectionBuilder.test.ts
index d342038f2a59..a04e00e1259c 100644
--- a/src/SignalR/clients/ts/signalr/tests/HubConnectionBuilder.test.ts
+++ b/src/SignalR/clients/ts/signalr/tests/HubConnectionBuilder.test.ts
@@ -384,6 +384,28 @@ describe("HubConnectionBuilder", () => {
expect(builder.reconnectPolicy!.nextRetryDelayInMilliseconds(retryContextFinal)).toBe(null);
});
+
+ it("can configure serverTimeoutInMilliseconds for HubConnection", async () => {
+ const milliseconds = 60000;
+
+ const connection = createConnectionBuilder()
+ .withUrl("http://example.com")
+ .withServerTimeout(milliseconds)
+ .build();
+
+ expect(connection.serverTimeoutInMilliseconds).toBe(milliseconds);
+ });
+
+ it("can configure keepAliveIntervalInMilliseconds for HubConnection", async () => {
+ const milliseconds = 60000;
+
+ const connection = createConnectionBuilder()
+ .withUrl("http://example.com")
+ .withKeepAliveInterval(milliseconds)
+ .build();
+
+ expect(connection.keepAliveIntervalInMilliseconds).toBe(milliseconds);
+ });
});
class CaptureLogger implements ILogger {