From 6ce2041c863fa8f43f5078429e8ff441743627b5 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 21 Jun 2026 09:07:37 +0000
Subject: [PATCH 1/3] Initial plan
From c76fad45aa5a3fecae39dab9e2a2a5f1a5cae402 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 21 Jun 2026 09:22:18 +0000
Subject: [PATCH 2/3] Address BrowserConfiguration API review feedback (rename
to BrowserOptions, reshape API, preserve wire format)
Co-authored-by: javiercn <6995051+javiercn@users.noreply.github.com>
---
.../BrowserConfiguration.cs | 26 -------
.../BrowserConfiguration/BrowserOptions.cs | 29 +++++++
....cs => InteractiveServerBrowserOptions.cs} | 12 +--
.../BrowserConfiguration/SsrBrowserOptions.cs | 9 ++-
.../WebAssemblyBrowserOptions.cs | 8 +-
.../Components/src/PublicAPI.Unshipped.txt | 44 +++++------
...=> BrowserOptionsHttpContextExtensions.cs} | 22 +++---
.../BrowserConfiguration/ConfigureBrowser.cs | 20 ++---
...entsEndpointConventionBuilderExtensions.cs | 16 ++--
.../Endpoints/src/PublicAPI.Unshipped.txt | 10 +--
.../BrowserConfigurationJsonContext.cs | 4 +-
.../BrowserConfigurationWireModel.cs | 77 +++++++++++++++++++
.../EndpointHtmlRenderer.Streaming.cs | 5 +-
.../RazorComponentEndpointsStartup.cs | 2 +-
14 files changed, 182 insertions(+), 102 deletions(-)
delete mode 100644 src/Components/Components/src/BrowserConfiguration/BrowserConfiguration.cs
create mode 100644 src/Components/Components/src/BrowserConfiguration/BrowserOptions.cs
rename src/Components/Components/src/BrowserConfiguration/{ServerBrowserOptions.cs => InteractiveServerBrowserOptions.cs} (67%)
rename src/Components/Endpoints/src/BrowserConfiguration/{BrowserConfigurationHttpContextExtensions.cs => BrowserOptionsHttpContextExtensions.cs} (56%)
create mode 100644 src/Components/Endpoints/src/Rendering/BrowserConfigurationWireModel.cs
diff --git a/src/Components/Components/src/BrowserConfiguration/BrowserConfiguration.cs b/src/Components/Components/src/BrowserConfiguration/BrowserConfiguration.cs
deleted file mode 100644
index 8883f202376b..000000000000
--- a/src/Components/Components/src/BrowserConfiguration/BrowserConfiguration.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-namespace Microsoft.AspNetCore.Components;
-
-///
-/// Configuration that flows from the server to the Blazor client in the browser
-/// via a DOM comment. Only serializable options; callbacks stay with JS initializers.
-///
-public sealed class BrowserConfiguration
-{
- ///
- /// The log level for the Blazor JS runtime. Applies to all render modes.
- /// Maps to WebStartOptions.logLevel.
- ///
- public int? LogLevel { get; set; }
-
- /// WebAssembly-specific options.
- public WebAssemblyBrowserOptions WebAssembly { get; set; } = new();
-
- /// Server/Circuit-specific options.
- public ServerBrowserOptions Server { get; set; } = new();
-
- /// SSR-specific options.
- public SsrBrowserOptions Ssr { get; set; } = new();
-}
diff --git a/src/Components/Components/src/BrowserConfiguration/BrowserOptions.cs b/src/Components/Components/src/BrowserConfiguration/BrowserOptions.cs
new file mode 100644
index 000000000000..000283997b6c
--- /dev/null
+++ b/src/Components/Components/src/BrowserConfiguration/BrowserOptions.cs
@@ -0,0 +1,29 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Microsoft.Extensions.Logging;
+
+namespace Microsoft.AspNetCore.Components;
+
+///
+/// Options that flow from the server to the Blazor client in the browser
+/// via a DOM comment. Only serializable options are included; callbacks stay
+/// with JS initializers.
+///
+public sealed class BrowserOptions
+{
+ ///
+ /// Gets or sets the log level for the Blazor JS runtime. Applies to all render modes.
+ /// Maps to WebStartOptions.logLevel.
+ ///
+ public LogLevel? LogLevel { get; set; }
+
+ /// Gets the WebAssembly-specific options.
+ public WebAssemblyBrowserOptions WebAssembly { get; } = new();
+
+ /// Gets the interactive server (circuit) specific options.
+ public InteractiveServerBrowserOptions Server { get; } = new();
+
+ /// Gets the SSR-specific options.
+ public SsrBrowserOptions Ssr { get; } = new();
+}
diff --git a/src/Components/Components/src/BrowserConfiguration/ServerBrowserOptions.cs b/src/Components/Components/src/BrowserConfiguration/InteractiveServerBrowserOptions.cs
similarity index 67%
rename from src/Components/Components/src/BrowserConfiguration/ServerBrowserOptions.cs
rename to src/Components/Components/src/BrowserConfiguration/InteractiveServerBrowserOptions.cs
index b8aee08f950e..b61e7f26567f 100644
--- a/src/Components/Components/src/BrowserConfiguration/ServerBrowserOptions.cs
+++ b/src/Components/Components/src/BrowserConfiguration/InteractiveServerBrowserOptions.cs
@@ -4,27 +4,27 @@
namespace Microsoft.AspNetCore.Components;
///
-/// Serializable subset of CircuitStartOptions.
+/// Serializable subset of CircuitStartOptions for the interactive server render mode.
/// Non-serializable options (configureSignalR, reconnectionHandler,
/// circuitHandlers) must use Blazor.start() or JS initializers.
///
-public sealed class ServerBrowserOptions
+public sealed class InteractiveServerBrowserOptions
{
///
- /// Maximum reconnection attempts before giving up.
+ /// Gets or sets the maximum reconnection attempts before giving up.
/// Maps to CircuitStartOptions.reconnectionOptions.maxRetries.
///
public int? ReconnectionMaxRetries { get; set; }
///
- /// Base interval in milliseconds between reconnection attempts (scalar form).
+ /// Gets or sets the base interval between reconnection attempts (scalar form).
/// The function form (retryCount, currentMs) => number requires JS.
/// Maps to CircuitStartOptions.reconnectionOptions.retryIntervalMilliseconds.
///
- public int? ReconnectionRetryIntervalMilliseconds { get; set; }
+ public TimeSpan? ReconnectionRetryInterval { get; set; }
///
- /// CSS ID of the reconnection dialog element.
+ /// Gets or sets the CSS ID of the reconnection dialog element.
/// Maps to CircuitStartOptions.reconnectionOptions.dialogId.
///
public string? ReconnectionDialogId { get; set; }
diff --git a/src/Components/Components/src/BrowserConfiguration/SsrBrowserOptions.cs b/src/Components/Components/src/BrowserConfiguration/SsrBrowserOptions.cs
index dfd78a0b0ae9..bac9b333ee8a 100644
--- a/src/Components/Components/src/BrowserConfiguration/SsrBrowserOptions.cs
+++ b/src/Components/Components/src/BrowserConfiguration/SsrBrowserOptions.cs
@@ -9,14 +9,15 @@ namespace Microsoft.AspNetCore.Components;
public sealed class SsrBrowserOptions
{
///
- /// When true, disables DOM preservation during enhanced navigation.
+ /// Gets or sets a value indicating whether the DOM is preserved during enhanced navigation.
+ /// When , DOM preservation is disabled. leaves the value unset.
/// Maps to SsrStartOptions.disableDomPreservation.
///
- public bool? DisableDomPreservation { get; set; }
+ public bool? PreserveDom { get; set; }
///
- /// Timeout in milliseconds before an inactive circuit is disposed.
+ /// Gets or sets the timeout before an inactive circuit is disposed.
/// Maps to SsrStartOptions.circuitInactivityTimeoutMs.
///
- public int? CircuitInactivityTimeoutMs { get; set; }
+ public TimeSpan? CircuitInactivityTimeout { get; set; }
}
diff --git a/src/Components/Components/src/BrowserConfiguration/WebAssemblyBrowserOptions.cs b/src/Components/Components/src/BrowserConfiguration/WebAssemblyBrowserOptions.cs
index 6eeccd428b2b..fbcef2476909 100644
--- a/src/Components/Components/src/BrowserConfiguration/WebAssemblyBrowserOptions.cs
+++ b/src/Components/Components/src/BrowserConfiguration/WebAssemblyBrowserOptions.cs
@@ -11,20 +11,20 @@ namespace Microsoft.AspNetCore.Components;
public sealed class WebAssemblyBrowserOptions
{
///
- /// Hosting environment name (e.g., "Development", "Production").
+ /// Gets or sets the hosting environment name (e.g., "Development", "Production").
/// Maps to WebAssemblyStartOptions.environment.
///
public string? EnvironmentName { get; set; }
///
- /// Application culture in BCP 47 format (e.g., "en-US").
+ /// Gets or sets the application culture in BCP 47 format (e.g., "en-US").
/// Maps to WebAssemblyStartOptions.applicationCulture.
///
public string? ApplicationCulture { get; set; }
///
- /// Environment variables for the .NET WebAssembly runtime.
+ /// Gets the environment variables for the .NET WebAssembly runtime.
/// Use for OTEL endpoints, service URLs, etc.
///
- public Dictionary EnvironmentVariables { get; set; } = new();
+ public IDictionary EnvironmentVariables { get; } = new Dictionary();
}
diff --git a/src/Components/Components/src/PublicAPI.Unshipped.txt b/src/Components/Components/src/PublicAPI.Unshipped.txt
index 1860c583402f..ffb60e308c9a 100644
--- a/src/Components/Components/src/PublicAPI.Unshipped.txt
+++ b/src/Components/Components/src/PublicAPI.Unshipped.txt
@@ -13,35 +13,31 @@ Microsoft.AspNetCore.Components.IComponentPropertyActivator.GetActivator(System.
*REMOVED*Microsoft.AspNetCore.Components.Routing.Router.PreferExactMatches.get -> bool
*REMOVED*Microsoft.AspNetCore.Components.Routing.Router.PreferExactMatches.set -> void
static Microsoft.Extensions.DependencyInjection.CascadingValueServiceCollectionExtensions.TryAddCascadingValueSupplier(this Microsoft.Extensions.DependencyInjection.IServiceCollection! serviceCollection, System.Func!>! subscribeFactory) -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
-Microsoft.AspNetCore.Components.BrowserConfiguration
-Microsoft.AspNetCore.Components.BrowserConfiguration.BrowserConfiguration() -> void
-Microsoft.AspNetCore.Components.BrowserConfiguration.LogLevel.get -> int?
-Microsoft.AspNetCore.Components.BrowserConfiguration.LogLevel.set -> void
-Microsoft.AspNetCore.Components.BrowserConfiguration.Server.get -> Microsoft.AspNetCore.Components.ServerBrowserOptions!
-Microsoft.AspNetCore.Components.BrowserConfiguration.Server.set -> void
-Microsoft.AspNetCore.Components.BrowserConfiguration.Ssr.get -> Microsoft.AspNetCore.Components.SsrBrowserOptions!
-Microsoft.AspNetCore.Components.BrowserConfiguration.Ssr.set -> void
-Microsoft.AspNetCore.Components.BrowserConfiguration.WebAssembly.get -> Microsoft.AspNetCore.Components.WebAssemblyBrowserOptions!
-Microsoft.AspNetCore.Components.BrowserConfiguration.WebAssembly.set -> void
-Microsoft.AspNetCore.Components.ServerBrowserOptions
-Microsoft.AspNetCore.Components.ServerBrowserOptions.ServerBrowserOptions() -> void
-Microsoft.AspNetCore.Components.ServerBrowserOptions.ReconnectionDialogId.get -> string?
-Microsoft.AspNetCore.Components.ServerBrowserOptions.ReconnectionDialogId.set -> void
-Microsoft.AspNetCore.Components.ServerBrowserOptions.ReconnectionMaxRetries.get -> int?
-Microsoft.AspNetCore.Components.ServerBrowserOptions.ReconnectionMaxRetries.set -> void
-Microsoft.AspNetCore.Components.ServerBrowserOptions.ReconnectionRetryIntervalMilliseconds.get -> int?
-Microsoft.AspNetCore.Components.ServerBrowserOptions.ReconnectionRetryIntervalMilliseconds.set -> void
+Microsoft.AspNetCore.Components.BrowserOptions
+Microsoft.AspNetCore.Components.BrowserOptions.BrowserOptions() -> void
+Microsoft.AspNetCore.Components.BrowserOptions.LogLevel.get -> Microsoft.Extensions.Logging.LogLevel?
+Microsoft.AspNetCore.Components.BrowserOptions.LogLevel.set -> void
+Microsoft.AspNetCore.Components.BrowserOptions.Server.get -> Microsoft.AspNetCore.Components.InteractiveServerBrowserOptions!
+Microsoft.AspNetCore.Components.BrowserOptions.Ssr.get -> Microsoft.AspNetCore.Components.SsrBrowserOptions!
+Microsoft.AspNetCore.Components.BrowserOptions.WebAssembly.get -> Microsoft.AspNetCore.Components.WebAssemblyBrowserOptions!
+Microsoft.AspNetCore.Components.InteractiveServerBrowserOptions
+Microsoft.AspNetCore.Components.InteractiveServerBrowserOptions.InteractiveServerBrowserOptions() -> void
+Microsoft.AspNetCore.Components.InteractiveServerBrowserOptions.ReconnectionDialogId.get -> string?
+Microsoft.AspNetCore.Components.InteractiveServerBrowserOptions.ReconnectionDialogId.set -> void
+Microsoft.AspNetCore.Components.InteractiveServerBrowserOptions.ReconnectionMaxRetries.get -> int?
+Microsoft.AspNetCore.Components.InteractiveServerBrowserOptions.ReconnectionMaxRetries.set -> void
+Microsoft.AspNetCore.Components.InteractiveServerBrowserOptions.ReconnectionRetryInterval.get -> System.TimeSpan?
+Microsoft.AspNetCore.Components.InteractiveServerBrowserOptions.ReconnectionRetryInterval.set -> void
Microsoft.AspNetCore.Components.SsrBrowserOptions
Microsoft.AspNetCore.Components.SsrBrowserOptions.SsrBrowserOptions() -> void
-Microsoft.AspNetCore.Components.SsrBrowserOptions.CircuitInactivityTimeoutMs.get -> int?
-Microsoft.AspNetCore.Components.SsrBrowserOptions.CircuitInactivityTimeoutMs.set -> void
-Microsoft.AspNetCore.Components.SsrBrowserOptions.DisableDomPreservation.get -> bool?
-Microsoft.AspNetCore.Components.SsrBrowserOptions.DisableDomPreservation.set -> void
+Microsoft.AspNetCore.Components.SsrBrowserOptions.CircuitInactivityTimeout.get -> System.TimeSpan?
+Microsoft.AspNetCore.Components.SsrBrowserOptions.CircuitInactivityTimeout.set -> void
+Microsoft.AspNetCore.Components.SsrBrowserOptions.PreserveDom.get -> bool?
+Microsoft.AspNetCore.Components.SsrBrowserOptions.PreserveDom.set -> void
Microsoft.AspNetCore.Components.WebAssemblyBrowserOptions
Microsoft.AspNetCore.Components.WebAssemblyBrowserOptions.WebAssemblyBrowserOptions() -> void
Microsoft.AspNetCore.Components.WebAssemblyBrowserOptions.ApplicationCulture.get -> string?
Microsoft.AspNetCore.Components.WebAssemblyBrowserOptions.ApplicationCulture.set -> void
Microsoft.AspNetCore.Components.WebAssemblyBrowserOptions.EnvironmentName.get -> string?
Microsoft.AspNetCore.Components.WebAssemblyBrowserOptions.EnvironmentName.set -> void
-Microsoft.AspNetCore.Components.WebAssemblyBrowserOptions.EnvironmentVariables.get -> System.Collections.Generic.Dictionary!
-Microsoft.AspNetCore.Components.WebAssemblyBrowserOptions.EnvironmentVariables.set -> void
+Microsoft.AspNetCore.Components.WebAssemblyBrowserOptions.EnvironmentVariables.get -> System.Collections.Generic.IDictionary!
diff --git a/src/Components/Endpoints/src/BrowserConfiguration/BrowserConfigurationHttpContextExtensions.cs b/src/Components/Endpoints/src/BrowserConfiguration/BrowserOptionsHttpContextExtensions.cs
similarity index 56%
rename from src/Components/Endpoints/src/BrowserConfiguration/BrowserConfigurationHttpContextExtensions.cs
rename to src/Components/Endpoints/src/BrowserConfiguration/BrowserOptionsHttpContextExtensions.cs
index a5d1dc07a145..bd41b162f3e8 100644
--- a/src/Components/Endpoints/src/BrowserConfiguration/BrowserConfigurationHttpContextExtensions.cs
+++ b/src/Components/Endpoints/src/BrowserConfiguration/BrowserOptionsHttpContextExtensions.cs
@@ -1,34 +1,36 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using Microsoft.AspNetCore.Components;
+using Microsoft.AspNetCore.Http;
-namespace Microsoft.AspNetCore.Http;
+namespace Microsoft.AspNetCore.Components;
///
-/// Extension methods on for accessing .
+/// Extension methods on for accessing .
///
-public static class BrowserConfigurationHttpContextExtensions
+public static class BrowserOptionsHttpContextExtensions
{
private static readonly object Key = new();
///
- /// Gets the for the current request.
+ /// Gets the for the current request.
/// If not already set, seeds from endpoint metadata or creates a new instance.
///
/// The .
- /// The for the current request.
- public static BrowserConfiguration GetBrowserConfiguration(this HttpContext context)
+ /// The for the current request.
+ public static BrowserOptions GetBrowserOptions(this HttpContext context)
{
+ ArgumentNullException.ThrowIfNull(context);
+
if (!context.Items.TryGetValue(Key, out var result))
{
// Seed from endpoint metadata if available
- var metadataConfig = context.GetEndpoint()?.Metadata.GetMetadata();
- var config = metadataConfig ?? new BrowserConfiguration();
+ var metadataConfig = context.GetEndpoint()?.Metadata.GetMetadata();
+ var config = metadataConfig ?? new BrowserOptions();
context.Items[Key] = config;
return config;
}
- return (BrowserConfiguration)result!;
+ return (BrowserOptions)result!;
}
}
diff --git a/src/Components/Endpoints/src/BrowserConfiguration/ConfigureBrowser.cs b/src/Components/Endpoints/src/BrowserConfiguration/ConfigureBrowser.cs
index 5d8fac5c1c8a..cbd66495e8d9 100644
--- a/src/Components/Endpoints/src/BrowserConfiguration/ConfigureBrowser.cs
+++ b/src/Components/Endpoints/src/BrowserConfiguration/ConfigureBrowser.cs
@@ -7,8 +7,8 @@ namespace Microsoft.AspNetCore.Components;
///
/// A component that configures the Blazor browser runtime by merging
-/// configuration into the on the current
-/// . The merged configuration is emitted as
+/// options into the on the current
+/// . The merged options are emitted as
/// a <!--Blazor-Configuration:{...}--> DOM comment by the renderer.
///
public sealed class ConfigureBrowser : IComponent
@@ -16,10 +16,10 @@ public sealed class ConfigureBrowser : IComponent
private RenderHandle _renderHandle;
///
- /// Gets or sets the to merge.
+ /// Gets or sets the to merge.
///
[Parameter, EditorRequired]
- public BrowserConfiguration Configuration { get; set; } = default!;
+ public BrowserOptions Options { get; set; } = default!;
///
/// Gets or sets the for the current request.
@@ -38,14 +38,14 @@ Task IComponent.SetParametersAsync(ParameterView parameters)
if (HttpContext is not null)
{
- var existing = HttpContext.GetBrowserConfiguration();
- MergeInto(existing, Configuration);
+ var existing = HttpContext.GetBrowserOptions();
+ MergeInto(existing, Options);
}
return Task.CompletedTask;
}
- internal static void MergeInto(BrowserConfiguration target, BrowserConfiguration source)
+ internal static void MergeInto(BrowserOptions target, BrowserOptions source)
{
target.LogLevel = source.LogLevel ?? target.LogLevel;
@@ -59,11 +59,11 @@ internal static void MergeInto(BrowserConfiguration target, BrowserConfiguration
// Server
target.Server.ReconnectionMaxRetries = source.Server.ReconnectionMaxRetries ?? target.Server.ReconnectionMaxRetries;
- target.Server.ReconnectionRetryIntervalMilliseconds = source.Server.ReconnectionRetryIntervalMilliseconds ?? target.Server.ReconnectionRetryIntervalMilliseconds;
+ target.Server.ReconnectionRetryInterval = source.Server.ReconnectionRetryInterval ?? target.Server.ReconnectionRetryInterval;
target.Server.ReconnectionDialogId = source.Server.ReconnectionDialogId ?? target.Server.ReconnectionDialogId;
// SSR
- target.Ssr.DisableDomPreservation = source.Ssr.DisableDomPreservation ?? target.Ssr.DisableDomPreservation;
- target.Ssr.CircuitInactivityTimeoutMs = source.Ssr.CircuitInactivityTimeoutMs ?? target.Ssr.CircuitInactivityTimeoutMs;
+ target.Ssr.PreserveDom = source.Ssr.PreserveDom ?? target.Ssr.PreserveDom;
+ target.Ssr.CircuitInactivityTimeout = source.Ssr.CircuitInactivityTimeout ?? target.Ssr.CircuitInactivityTimeout;
}
}
diff --git a/src/Components/Endpoints/src/Builder/RazorComponentsEndpointConventionBuilderExtensions.cs b/src/Components/Endpoints/src/Builder/RazorComponentsEndpointConventionBuilderExtensions.cs
index 754663d2cd4b..79c64f0d646d 100644
--- a/src/Components/Endpoints/src/Builder/RazorComponentsEndpointConventionBuilderExtensions.cs
+++ b/src/Components/Endpoints/src/Builder/RazorComponentsEndpointConventionBuilderExtensions.cs
@@ -65,25 +65,25 @@ public static RazorComponentsEndpointConventionBuilder WithStaticAssets(
}
///
- /// Configures a that will be emitted as a DOM comment
+ /// Configures a that will be emitted as a DOM comment
/// to the browser for all Razor component endpoints.
///
/// The .
- /// An action to configure the .
+ /// An action to configure the .
/// The .
- public static RazorComponentsEndpointConventionBuilder WithBrowserConfiguration(
+ public static RazorComponentsEndpointConventionBuilder WithBrowserOptions(
this RazorComponentsEndpointConventionBuilder builder,
- Action configure)
+ Action configureOptions)
{
ArgumentNullException.ThrowIfNull(builder);
- ArgumentNullException.ThrowIfNull(configure);
+ ArgumentNullException.ThrowIfNull(configureOptions);
- var config = new BrowserConfiguration();
- configure(config);
+ var options = new BrowserOptions();
+ configureOptions(options);
builder.Add(endpointBuilder =>
{
- endpointBuilder.Metadata.Add(config);
+ endpointBuilder.Metadata.Add(options);
});
return builder;
diff --git a/src/Components/Endpoints/src/PublicAPI.Unshipped.txt b/src/Components/Endpoints/src/PublicAPI.Unshipped.txt
index e26fbfcce577..82f2207edc20 100644
--- a/src/Components/Endpoints/src/PublicAPI.Unshipped.txt
+++ b/src/Components/Endpoints/src/PublicAPI.Unshipped.txt
@@ -15,10 +15,10 @@ Microsoft.AspNetCore.Components.ITempData.Keep(string! key) -> void
Microsoft.AspNetCore.Components.ITempData.Peek(string! key) -> object?
Microsoft.AspNetCore.Components.ConfigureBrowser
Microsoft.AspNetCore.Components.ConfigureBrowser.ConfigureBrowser() -> void
-Microsoft.AspNetCore.Components.ConfigureBrowser.Configuration.get -> Microsoft.AspNetCore.Components.BrowserConfiguration!
-Microsoft.AspNetCore.Components.ConfigureBrowser.Configuration.set -> void
+Microsoft.AspNetCore.Components.ConfigureBrowser.Options.get -> Microsoft.AspNetCore.Components.BrowserOptions!
+Microsoft.AspNetCore.Components.ConfigureBrowser.Options.set -> void
Microsoft.AspNetCore.Components.ConfigureBrowser.HttpContext.get -> Microsoft.AspNetCore.Http.HttpContext?
Microsoft.AspNetCore.Components.ConfigureBrowser.HttpContext.set -> void
-Microsoft.AspNetCore.Http.BrowserConfigurationHttpContextExtensions
-static Microsoft.AspNetCore.Http.BrowserConfigurationHttpContextExtensions.GetBrowserConfiguration(this Microsoft.AspNetCore.Http.HttpContext! context) -> Microsoft.AspNetCore.Components.BrowserConfiguration!
-static Microsoft.AspNetCore.Builder.RazorComponentsEndpointConventionBuilderExtensions.WithBrowserConfiguration(this Microsoft.AspNetCore.Builder.RazorComponentsEndpointConventionBuilder! builder, System.Action! configure) -> Microsoft.AspNetCore.Builder.RazorComponentsEndpointConventionBuilder!
+Microsoft.AspNetCore.Components.BrowserOptionsHttpContextExtensions
+static Microsoft.AspNetCore.Components.BrowserOptionsHttpContextExtensions.GetBrowserOptions(this Microsoft.AspNetCore.Http.HttpContext! context) -> Microsoft.AspNetCore.Components.BrowserOptions!
+static Microsoft.AspNetCore.Builder.RazorComponentsEndpointConventionBuilderExtensions.WithBrowserOptions(this Microsoft.AspNetCore.Builder.RazorComponentsEndpointConventionBuilder! builder, System.Action! configureOptions) -> Microsoft.AspNetCore.Builder.RazorComponentsEndpointConventionBuilder!
diff --git a/src/Components/Endpoints/src/Rendering/BrowserConfigurationJsonContext.cs b/src/Components/Endpoints/src/Rendering/BrowserConfigurationJsonContext.cs
index ace7473c1956..5bd3ec920e65 100644
--- a/src/Components/Endpoints/src/Rendering/BrowserConfigurationJsonContext.cs
+++ b/src/Components/Endpoints/src/Rendering/BrowserConfigurationJsonContext.cs
@@ -3,12 +3,12 @@
using System.Text.Json.Serialization;
-namespace Microsoft.AspNetCore.Components;
+namespace Microsoft.AspNetCore.Components.Endpoints;
[JsonSourceGenerationOptions(
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull)]
-[JsonSerializable(typeof(BrowserConfiguration))]
+[JsonSerializable(typeof(BrowserConfigurationWireModel))]
internal partial class BrowserConfigurationJsonContext : JsonSerializerContext
{
}
diff --git a/src/Components/Endpoints/src/Rendering/BrowserConfigurationWireModel.cs b/src/Components/Endpoints/src/Rendering/BrowserConfigurationWireModel.cs
new file mode 100644
index 000000000000..7540448ba93c
--- /dev/null
+++ b/src/Components/Endpoints/src/Rendering/BrowserConfigurationWireModel.cs
@@ -0,0 +1,77 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace Microsoft.AspNetCore.Components.Endpoints;
+
+// Internal wire representation of . The serialized format
+// is consumed by the Blazor JS runtime and is treated as a versioned/internal contract,
+// so it is decoupled from the public options shape. Durations are emitted as milliseconds
+// and positive options (e.g. PreserveDom) are mapped to the JS negative form.
+internal sealed class BrowserConfigurationWireModel
+{
+ public int? LogLevel { get; set; }
+
+ public WebAssemblyWireModel WebAssembly { get; set; } = new();
+
+ public ServerWireModel Server { get; set; } = new();
+
+ public SsrWireModel Ssr { get; set; } = new();
+
+ public static BrowserConfigurationWireModel FromOptions(BrowserOptions options)
+ {
+ var wire = new BrowserConfigurationWireModel
+ {
+ LogLevel = options.LogLevel is { } logLevel ? (int)logLevel : null,
+ WebAssembly = new WebAssemblyWireModel
+ {
+ EnvironmentName = options.WebAssembly.EnvironmentName,
+ ApplicationCulture = options.WebAssembly.ApplicationCulture,
+ EnvironmentVariables = options.WebAssembly.EnvironmentVariables.Count > 0
+ ? new Dictionary(options.WebAssembly.EnvironmentVariables)
+ : null,
+ },
+ Server = new ServerWireModel
+ {
+ ReconnectionMaxRetries = options.Server.ReconnectionMaxRetries,
+ ReconnectionRetryIntervalMilliseconds = options.Server.ReconnectionRetryInterval is { } interval
+ ? (int)interval.TotalMilliseconds
+ : null,
+ ReconnectionDialogId = options.Server.ReconnectionDialogId,
+ },
+ Ssr = new SsrWireModel
+ {
+ DisableDomPreservation = options.Ssr.PreserveDom is { } preserveDom ? !preserveDom : null,
+ CircuitInactivityTimeoutMs = options.Ssr.CircuitInactivityTimeout is { } timeout
+ ? (int)timeout.TotalMilliseconds
+ : null,
+ },
+ };
+
+ return wire;
+ }
+
+ internal sealed class WebAssemblyWireModel
+ {
+ public string? EnvironmentName { get; set; }
+
+ public string? ApplicationCulture { get; set; }
+
+ public IDictionary? EnvironmentVariables { get; set; }
+ }
+
+ internal sealed class ServerWireModel
+ {
+ public int? ReconnectionMaxRetries { get; set; }
+
+ public int? ReconnectionRetryIntervalMilliseconds { get; set; }
+
+ public string? ReconnectionDialogId { get; set; }
+ }
+
+ internal sealed class SsrWireModel
+ {
+ public bool? DisableDomPreservation { get; set; }
+
+ public int? CircuitInactivityTimeoutMs { get; set; }
+ }
+}
diff --git a/src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.Streaming.cs b/src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.Streaming.cs
index 2890acec7005..ddf01f537795 100644
--- a/src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.Streaming.cs
+++ b/src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.Streaming.cs
@@ -344,7 +344,7 @@ private void EmitBrowserConfigurationOnce(TextWriter output)
_browserConfigurationEmitted = true;
- var config = _httpContext.GetBrowserConfiguration();
+ var config = _httpContext.GetBrowserOptions();
// Apply framework defaults: environment name and tooling env vars
var hostEnvironment = _httpContext.RequestServices.GetRequiredService();
@@ -360,7 +360,8 @@ private void EmitBrowserConfigurationOnce(TextWriter output)
config.WebAssembly.EnvironmentVariables.TryAdd("__ASPNETCORE_BROWSER_TOOLS", s_aspnetcoreBrowserTools);
}
- var configJson = JsonSerializer.Serialize(config, BrowserConfigurationJsonContext.Default.BrowserConfiguration);
+ var wireModel = BrowserConfigurationWireModel.FromOptions(config);
+ var configJson = JsonSerializer.Serialize(wireModel, BrowserConfigurationJsonContext.Default.BrowserConfigurationWireModel);
var configBase64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(configJson));
output.Write("