diff --git a/src/Components/Server/src/Builder/ServerComponentsEndpointOptions.cs b/src/Components/Server/src/Builder/ServerComponentsEndpointOptions.cs
index 6cccf9db1656..7567b3410a4a 100644
--- a/src/Components/Server/src/Builder/ServerComponentsEndpointOptions.cs
+++ b/src/Components/Server/src/Builder/ServerComponentsEndpointOptions.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Connections;
namespace Microsoft.AspNetCore.Components.Server;
@@ -53,4 +54,13 @@ public class ServerComponentsEndpointOptions
/// defined in will be applied.
///
public Func? ConfigureWebSocketAcceptContext { get; set; }
+
+ ///
+ /// Gets or sets a callback to configure the used by the SignalR connection.
+ ///
+ ///
+ /// This allows configuring options such as ,
+ /// transport options, authorization data, and other connection-level settings.
+ ///
+ public Action? ConfigureConnection { get; set; }
}
diff --git a/src/Components/Server/src/DependencyInjection/ServerRazorComponentsBuilderExtensions.cs b/src/Components/Server/src/DependencyInjection/ServerRazorComponentsBuilderExtensions.cs
index 9b151b880c3d..3e6e08c45fa1 100644
--- a/src/Components/Server/src/DependencyInjection/ServerRazorComponentsBuilderExtensions.cs
+++ b/src/Components/Server/src/DependencyInjection/ServerRazorComponentsBuilderExtensions.cs
@@ -69,7 +69,10 @@ public override IEnumerable GetEndpointBuilders(
}
var endpointRouteBuilder = new EndpointRouteBuilder(Services, applicationBuilder);
- var hub = endpointRouteBuilder.MapBlazorHub("/_blazor");
+ var serverRenderMode = (InternalServerRenderMode)renderMode;
+ var hub = serverRenderMode.Options?.ConfigureConnection is not null
+ ? endpointRouteBuilder.MapBlazorHub("/_blazor", serverRenderMode.Options.ConfigureConnection)
+ : endpointRouteBuilder.MapBlazorHub("/_blazor");
if (renderMode is InternalServerRenderMode { Options.ConfigureWebSocketAcceptContext: var configureConnection, Options.DisableWebSocketCompression: var disableCompression } &&
(configureConnection is not null || !disableCompression))
diff --git a/src/Components/Server/src/PublicAPI.Unshipped.txt b/src/Components/Server/src/PublicAPI.Unshipped.txt
index 210a9b4fdd3c..cdf24aa3908b 100644
--- a/src/Components/Server/src/PublicAPI.Unshipped.txt
+++ b/src/Components/Server/src/PublicAPI.Unshipped.txt
@@ -7,3 +7,5 @@ Microsoft.AspNetCore.Components.Server.CircuitOptions.PersistedCircuitInMemoryMa
Microsoft.AspNetCore.Components.Server.CircuitOptions.PersistedCircuitInMemoryMaxRetained.set -> void
Microsoft.AspNetCore.Components.Server.CircuitOptions.PersistedCircuitInMemoryRetentionPeriod.get -> System.TimeSpan
Microsoft.AspNetCore.Components.Server.CircuitOptions.PersistedCircuitInMemoryRetentionPeriod.set -> void
+Microsoft.AspNetCore.Components.Server.ServerComponentsEndpointOptions.ConfigureConnection.get -> System.Action?
+Microsoft.AspNetCore.Components.Server.ServerComponentsEndpointOptions.ConfigureConnection.set -> void
diff --git a/src/Components/Server/test/ComponentEndpointRouteBuilderExtensionsTest.cs b/src/Components/Server/test/ComponentEndpointRouteBuilderExtensionsTest.cs
index 5d28dae0be1a..cccfba04125a 100644
--- a/src/Components/Server/test/ComponentEndpointRouteBuilderExtensionsTest.cs
+++ b/src/Components/Server/test/ComponentEndpointRouteBuilderExtensionsTest.cs
@@ -5,6 +5,7 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Connections;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
@@ -122,6 +123,30 @@ public void MapBlazorHub_AppliesFinalConventionsInFIFOOrder()
Assert.Equal(new[] { "first-in", "last-in" }, populatedMetadata);
}
+ [Fact]
+ public void ServerComponentsEndpointOptions_ConfigureConnection_CanBeSet()
+ {
+ // Arrange
+ var options = new ServerComponentsEndpointOptions();
+ var configureConnectionCalled = false;
+
+ // Act
+ options.ConfigureConnection = dispatcherOptions =>
+ {
+ configureConnectionCalled = true;
+ dispatcherOptions.CloseOnAuthenticationExpiration = true;
+ };
+
+ // Simulate calling the configuration
+ var dispatcherOptions = new HttpConnectionDispatcherOptions();
+ options.ConfigureConnection?.Invoke(dispatcherOptions);
+
+ // Assert
+ Assert.NotNull(options.ConfigureConnection);
+ Assert.True(configureConnectionCalled);
+ Assert.True(dispatcherOptions.CloseOnAuthenticationExpiration);
+ }
+
private IApplicationBuilder CreateAppBuilder()
{
var environment = new Mock();