Skip to content

Navigate with "replace" param #33751

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from
Jun 30, 2021
Merged

Navigate with "replace" param #33751

merged 20 commits into from
Jun 30, 2021

Conversation

SteveSandersonMS
Copy link
Member

@SteveSandersonMS SteveSandersonMS commented Jun 22, 2021

This is a continuation of the work at #25752

It's a surprisingly involved change for what seems like just adding an extra bool flag. Mainly this is because it happens to be on one of the extensibility seams so we have to work hard to ensure it's nonbreaking for existing NavigationManager subclasses (e.g., that people have made for tests).

The approach taken here is:

  • Existing calls to NavigateTo(string, bool=false) will continue to work, because of carefully adding a combination of overloads that retains both source and binary compatibility
  • Existing NavigationManager subclasses that override abstract void NavigateToCore(string, bool) will continue to work because the framework continues to call that as much as it can (i.e., whenever the caller doesn't specify replace=true).
  • New NavigationManager subclasses no longer need to override abstract void NavigateToCore(string, bool) - they can do if they want, but instead, it's sufficient to override virtual void NavigateToCore(string, NavigationOptions) since the new base class implementation of (string, bool) calls into it.

There is also a bunch of refactoring on the JS side because even though the previous code had both force and replace flags, it actually didn't support them both being true at the same time. Supporting this extra case made the existing code hard to read so I've restructured it for simplicity. AFAIK this should not result in any back-compat loss, even in extreme edge cases of unrecognized URL formats, because of retaining the distinction between url and absoluteUrl in the code paths.

/// If false, appends the new entry to the history stack.
/// </summary>
public bool ReplaceHistoryEntry { get; init; }
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In an earlier edition of this PR, NavigationOptions was a flags enum. I've changed it to a full-fledged struct because I don't want to get into this situation again in the future where we need to add some other option and have to multiply out the number of overloads and obscure rules for what methods you have to implement in subclasses.

With a struct, even if we need new options of type string, or rules about which combinations of options are legal to use simultaneously, it should be possible to model that (e.g., as different constructor overloads).

@@ -2,6 +2,8 @@
*REMOVED*static Microsoft.AspNetCore.Components.ParameterView.FromDictionary(System.Collections.Generic.IDictionary<string!, object!>! 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
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although these show as removed, there should be no back-compat loss (source or binary) because of adding new equivalents. I think our PublicAPI tooling doesn't reflect some details about how adding new optional params.

But if you're code-reviewing this, please check you agree with my claim here :)

@SteveSandersonMS SteveSandersonMS requested a review from a team June 23, 2021 10:16
@SteveSandersonMS SteveSandersonMS marked this pull request as ready for review June 23, 2021 10:16
@@ -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<System.Collections.Generic.IDictionary<string!, byte[]!>!>!
Microsoft.AspNetCore.Components.Lifetime.IComponentApplicationStateStore.PersistStateAsync(System.Collections.Generic.IReadOnlyDictionary<string!, byte[]!>! 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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this overload?

I think we should force people into using the navigation options directly and set ourselves for success in the future.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally I find:

navManager.NavigateTo("something", replace: true);

to be a lot more readable than:

navManager.NavigateTo("something", new NavigationOptions { ReplaceHistoryEntry = true });

However I understand it's always a subjective balance when we consider adding overloads just for convenience. It depends on how universal we think the convenience-overload pattern will be, and whether it will stand the test of time as being the only extra convenience we need, vs something that ends up getting multiplied out into many other overload variants. (I know you know this; just giving context for anyone else reading)

We do need at least to keep the NavigateTo(string, bool) overload for back-compat. To me it felt a bit rough if this other equally-often-used flag was not available in a similar shorthand format.

Shall we leave a final call on this until we get to API review, or do you feel strongly now?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't feel strongly about it, it was mainly a suggestion.

Comment on lines +69 to +73
// For back-compat, we need to accept multiple overloads
export function navigateTo(uri: string, options: NavigationOptions): void;
export function navigateTo(uri: string, forceLoad: boolean): void;
export function navigateTo(uri: string, forceLoad: boolean, replace: boolean): void;
export function navigateTo(uri: string, forceLoadOrOptions: NavigationOptions | boolean, replaceIfUsingOldOverload: boolean = false) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't seen this used in a while in TS 😄.

I believe navigateTo ends up in our internal namespace. The only thing that uses that overload is the auth bits in one place. I'm happy if you update those and avoid having to deal with the special case here, since we can consider this API internal and for our consumption, akin to private reflection.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's actually not within internal, however it's here

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blazor.navigateTo (the JS API) is very much public and supported. It's the only way to trigger a client-side Blazor navigation from JS code, so is certainly needed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I saw that later. If you want to update the auth package as part of this change to rely on that, It would be nice.

Copy link
Member

@javiercn javiercn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great!

@SteveSandersonMS SteveSandersonMS force-pushed the stevesa/navigate-replace branch from 0fd0c05 to 9ee3402 Compare June 29, 2021 14:57
@SteveSandersonMS
Copy link
Member Author

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 2 pipeline(s).

MariovanZeist and others added 18 commits June 30, 2021 13:18
…igateTo

So instead of pushing the new uri into the browser history, we replace the uri in the browser history
!!!IMPORTANT!!!!

I have also added a pragma to disable a warning which should NOT be disabled.
It's only added to get it reviewed and fixed.

#pragma warning disable RS0027 // Public API with optional parameter(s) should have the most parameters amongst its public overloads.
Is added to the NavigationManager

Before merging this should be addressed.
The forceLoad flag would be ignored if not loading the same Uri
@SteveSandersonMS SteveSandersonMS force-pushed the stevesa/navigate-replace branch from 7a18e65 to 4fb201b Compare June 30, 2021 12:31
@SteveSandersonMS SteveSandersonMS force-pushed the stevesa/navigate-replace branch from 1adc8cd to a68395e Compare June 30, 2021 13:50
@SteveSandersonMS SteveSandersonMS merged commit ed383aa into main Jun 30, 2021
@SteveSandersonMS SteveSandersonMS deleted the stevesa/navigate-replace branch June 30, 2021 15:40
@ghost ghost added this to the 6.0-preview7 milestone Jun 30, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-blazor Includes: Blazor, Razor Components
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants