diff --git a/src/Components/Components/src/NavigationManager.cs b/src/Components/Components/src/NavigationManager.cs
index e5752e669a38..fc59596f03c1 100644
--- a/src/Components/Components/src/NavigationManager.cs
+++ b/src/Components/Components/src/NavigationManager.cs
@@ -90,10 +90,46 @@ protected set
/// The destination URI. This can be absolute, or relative to the base URI
/// (as returned by ).
/// If true, bypasses client-side routing and forces the browser to load the new page from the server, whether or not the URI would normally be handled by the client-side router.
- public void NavigateTo(string uri, bool forceLoad = false)
+ public void NavigateTo(string uri, bool forceLoad) // This overload is for binary back-compat with < 6.0
+ => NavigateTo(uri, forceLoad, replace: false);
+
+ ///
+ /// Navigates to the specified URI.
+ ///
+ /// The destination URI. This can be absolute, or relative to the base URI
+ /// (as returned by ).
+ /// If true, bypasses client-side routing and forces the browser to load the new page from the server, whether or not the URI would normally be handled by the client-side router.
+ /// If true, replaces the currently entry in the history stack. If false, appends the new entry to the history stack.
+ public void NavigateTo(string uri, bool forceLoad = false, bool replace = false)
+ {
+ AssertInitialized();
+
+ if (replace)
+ {
+ NavigateToCore(uri, new NavigationOptions
+ {
+ ForceLoad = forceLoad,
+ ReplaceHistoryEntry = replace,
+ });
+ }
+ else
+ {
+ // For back-compatibility, we must call the (string, bool) overload of NavigateToCore from here,
+ // because that's the only overload guaranteed to be implemented in subclasses.
+ NavigateToCore(uri, forceLoad);
+ }
+ }
+
+ ///
+ /// Navigates to the specified URI.
+ ///
+ /// The destination URI. This can be absolute, or relative to the base URI
+ /// (as returned by ).
+ /// Provides additional .
+ public void NavigateTo(string uri, NavigationOptions options)
{
AssertInitialized();
- NavigateToCore(uri, forceLoad);
+ NavigateToCore(uri, options);
}
///
@@ -102,7 +138,21 @@ public void NavigateTo(string uri, bool forceLoad = false)
/// The destination URI. This can be absolute, or relative to the base URI
/// (as returned by ).
/// If true, bypasses client-side routing and forces the browser to load the new page from the server, whether or not the URI would normally be handled by the client-side router.
- protected abstract void NavigateToCore(string uri, bool forceLoad);
+ // The reason this overload exists and is virtual is for back-compat with < 6.0. Existing NavigationManager subclasses may
+ // already override this, so the framework needs to keep using it for the cases when only pre-6.0 options are used.
+ // However, for anyone implementing a new NavigationManager post-6.0, we don't want them to have to override this
+ // overload any more, so there's now a default implementation that calls the updated overload.
+ protected virtual void NavigateToCore(string uri, bool forceLoad)
+ => NavigateToCore(uri, new NavigationOptions { ForceLoad = forceLoad });
+
+ ///
+ /// Navigates to the specified URI.
+ ///
+ /// The destination URI. This can be absolute, or relative to the base URI
+ /// (as returned by ).
+ /// Provides additional .
+ protected virtual void NavigateToCore(string uri, NavigationOptions options) =>
+ throw new NotImplementedException($"The type {GetType().FullName} does not support supplying {nameof(NavigationOptions)}. To add support, that type should override {nameof(NavigateToCore)}(string uri, {nameof(NavigationOptions)} options).");
///
/// Called to initialize BaseURI and current URI before these values are used for the first time.
diff --git a/src/Components/Components/src/NavigationOptions.cs b/src/Components/Components/src/NavigationOptions.cs
new file mode 100644
index 000000000000..ea8d4995fab8
--- /dev/null
+++ b/src/Components/Components/src/NavigationOptions.cs
@@ -0,0 +1,22 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.AspNetCore.Components
+{
+ ///
+ /// Additional options for navigating to another URI.
+ ///
+ public readonly struct NavigationOptions
+ {
+ ///
+ /// If true, bypasses client-side routing and forces the browser to load the new page from the server, whether or not the URI would normally be handled by the client-side router.
+ ///
+ public bool ForceLoad { get; init; }
+
+ ///
+ /// If true, replaces the currently entry in the history stack.
+ /// If false, appends the new entry to the history stack.
+ ///
+ public bool ReplaceHistoryEntry { get; init; }
+ }
+}
diff --git a/src/Components/Components/src/PublicAPI.Unshipped.txt b/src/Components/Components/src/PublicAPI.Unshipped.txt
index efeeb3e4866c..8e6ae930e781 100644
--- a/src/Components/Components/src/PublicAPI.Unshipped.txt
+++ b/src/Components/Components/src/PublicAPI.Unshipped.txt
@@ -2,6 +2,8 @@
*REMOVED*static Microsoft.AspNetCore.Components.ParameterView.FromDictionary(System.Collections.Generic.IDictionary! parameters) -> Microsoft.AspNetCore.Components.ParameterView
*REMOVED*virtual Microsoft.AspNetCore.Components.RenderTree.Renderer.DispatchEventAsync(ulong eventHandlerId, Microsoft.AspNetCore.Components.RenderTree.EventFieldInfo! fieldInfo, System.EventArgs! eventArgs) -> System.Threading.Tasks.Task!
*REMOVED*readonly Microsoft.AspNetCore.Components.RenderTree.RenderTreeEdit.RemovedAttributeName -> string!
+*REMOVED*Microsoft.AspNetCore.Components.NavigationManager.NavigateTo(string! uri, bool forceLoad = false) -> void
+*REMOVED*abstract Microsoft.AspNetCore.Components.NavigationManager.NavigateToCore(string! uri, bool forceLoad) -> void
Microsoft.AspNetCore.Components.ComponentApplicationState
Microsoft.AspNetCore.Components.ComponentApplicationState.OnPersisting -> Microsoft.AspNetCore.Components.ComponentApplicationState.OnPersistingCallback!
Microsoft.AspNetCore.Components.ComponentApplicationState.OnPersistingCallback
@@ -29,6 +31,15 @@ Microsoft.AspNetCore.Components.Lifetime.ComponentApplicationLifetime.State.get
Microsoft.AspNetCore.Components.Lifetime.IComponentApplicationStateStore
Microsoft.AspNetCore.Components.Lifetime.IComponentApplicationStateStore.GetPersistedStateAsync() -> System.Threading.Tasks.Task!>!
Microsoft.AspNetCore.Components.Lifetime.IComponentApplicationStateStore.PersistStateAsync(System.Collections.Generic.IReadOnlyDictionary! state) -> System.Threading.Tasks.Task!
+Microsoft.AspNetCore.Components.NavigationManager.NavigateTo(string! uri, Microsoft.AspNetCore.Components.NavigationOptions options) -> void
+Microsoft.AspNetCore.Components.NavigationManager.NavigateTo(string! uri, bool forceLoad = false, bool replace = false) -> void
+Microsoft.AspNetCore.Components.NavigationManager.NavigateTo(string! uri, bool forceLoad) -> void
+Microsoft.AspNetCore.Components.NavigationOptions
+Microsoft.AspNetCore.Components.NavigationOptions.ForceLoad.get -> bool
+Microsoft.AspNetCore.Components.NavigationOptions.ForceLoad.init -> void
+Microsoft.AspNetCore.Components.NavigationOptions.NavigationOptions() -> void
+Microsoft.AspNetCore.Components.NavigationOptions.ReplaceHistoryEntry.get -> bool
+Microsoft.AspNetCore.Components.NavigationOptions.ReplaceHistoryEntry.init -> void
Microsoft.AspNetCore.Components.RenderHandle.IsHotReloading.get -> bool
Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder.Dispose() -> void
Microsoft.AspNetCore.Components.Routing.Router.PreferExactMatches.get -> bool
@@ -49,6 +60,8 @@ Microsoft.AspNetCore.Components.RenderTree.Renderer.GetEventArgsType(ulong event
abstract Microsoft.AspNetCore.Components.ErrorBoundaryBase.OnErrorAsync(System.Exception! exception) -> System.Threading.Tasks.Task!
override Microsoft.AspNetCore.Components.LayoutComponentBase.SetParametersAsync(Microsoft.AspNetCore.Components.ParameterView parameters) -> System.Threading.Tasks.Task!
static Microsoft.AspNetCore.Components.ParameterView.FromDictionary(System.Collections.Generic.IDictionary! parameters) -> Microsoft.AspNetCore.Components.ParameterView
+virtual Microsoft.AspNetCore.Components.NavigationManager.NavigateToCore(string! uri, Microsoft.AspNetCore.Components.NavigationOptions options) -> void
+virtual Microsoft.AspNetCore.Components.NavigationManager.NavigateToCore(string! uri, bool forceLoad) -> void
virtual Microsoft.AspNetCore.Components.RenderTree.Renderer.DispatchEventAsync(ulong eventHandlerId, Microsoft.AspNetCore.Components.RenderTree.EventFieldInfo? fieldInfo, System.EventArgs! eventArgs) -> System.Threading.Tasks.Task!
readonly Microsoft.AspNetCore.Components.RenderTree.RenderTreeEdit.RemovedAttributeName -> string?
*REMOVED*Microsoft.AspNetCore.Components.CascadingValue.Value.get -> TValue
diff --git a/src/Components/Components/test/Routing/RouterTest.cs b/src/Components/Components/test/Routing/RouterTest.cs
index e139d042bedc..206f675035c4 100644
--- a/src/Components/Components/test/Routing/RouterTest.cs
+++ b/src/Components/Components/test/Routing/RouterTest.cs
@@ -209,8 +209,6 @@ internal class TestNavigationManager : NavigationManager
public TestNavigationManager() =>
Initialize("https://www.example.com/subdir/", "https://www.example.com/subdir/jan");
- protected override void NavigateToCore(string uri, bool forceLoad) => throw new NotImplementedException();
-
public void NotifyLocationChanged(string uri, bool intercepted)
{
Uri = uri;
diff --git a/src/Components/Server/src/Circuits/RemoteNavigationManager.cs b/src/Components/Server/src/Circuits/RemoteNavigationManager.cs
index fc297563ab90..8a695dbd43c8 100644
--- a/src/Components/Server/src/Circuits/RemoteNavigationManager.cs
+++ b/src/Components/Server/src/Circuits/RemoteNavigationManager.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
+using System.Diagnostics.CodeAnalysis;
using Microsoft.AspNetCore.Components.Routing;
using Microsoft.Extensions.Logging;
using Microsoft.JSInterop;
@@ -65,9 +66,10 @@ public void NotifyLocationChanged(string uri, bool intercepted)
}
///
- protected override void NavigateToCore(string uri, bool forceLoad)
+ [DynamicDependency(DynamicallyAccessedMemberTypes.PublicProperties, typeof(NavigationOptions))]
+ protected override void NavigateToCore(string uri, NavigationOptions options)
{
- Log.RequestingNavigation(_logger, uri, forceLoad);
+ Log.RequestingNavigation(_logger, uri, options);
if (_jsRuntime == null)
{
@@ -75,20 +77,20 @@ protected override void NavigateToCore(string uri, bool forceLoad)
throw new NavigationException(absoluteUriString);
}
- _jsRuntime.InvokeAsync