Skip to content

Commit 35127bf

Browse files
[release/8.0-rc1] [Blazor] Add APIs for "enhanced refresh" (#50124)
* Add NavigationManager.Refresh() + tests * PR feedback * Add `forceReload` parameter --------- Co-authored-by: Mackinnon Buck <[email protected]>
1 parent b86599e commit 35127bf

File tree

18 files changed

+189
-19
lines changed

18 files changed

+189
-19
lines changed

src/Components/Components/src/NavigationManager.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,17 @@ protected virtual void NavigateToCore([StringSyntax(StringSyntaxAttribute.Uri)]
166166
protected virtual void NavigateToCore([StringSyntax(StringSyntaxAttribute.Uri)] string uri, NavigationOptions options) =>
167167
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).");
168168

169+
/// <summary>
170+
/// Refreshes the current page via request to the server.
171+
/// </summary>
172+
/// <remarks>
173+
/// If <paramref name="forceReload"/> is <c>true</c>, a full page reload will always be performed.
174+
/// Otherwise, the response HTML may be merged with the document's existing HTML to preserve client-side state,
175+
/// falling back on a full page reload if necessary.
176+
/// </remarks>
177+
public virtual void Refresh(bool forceReload = false)
178+
=> NavigateTo(Uri, forceLoad: true, replace: true);
179+
169180
/// <summary>
170181
/// Called to initialize BaseURI and current URI before these values are used for the first time.
171182
/// Override <see cref="EnsureInitialized" /> and call this method to dynamically calculate these values.

src/Components/Components/src/PublicAPI.Unshipped.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ static Microsoft.AspNetCore.Components.SupplyParameterFromQueryProviderServiceCo
101101
static Microsoft.Extensions.DependencyInjection.CascadingValueServiceCollectionExtensions.AddCascadingValue<TValue>(this Microsoft.Extensions.DependencyInjection.IServiceCollection! serviceCollection, string! name, System.Func<System.IServiceProvider!, TValue>! valueFactory) -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
102102
static Microsoft.Extensions.DependencyInjection.CascadingValueServiceCollectionExtensions.AddCascadingValue<TValue>(this Microsoft.Extensions.DependencyInjection.IServiceCollection! serviceCollection, System.Func<System.IServiceProvider!, Microsoft.AspNetCore.Components.CascadingValueSource<TValue>!>! sourceFactory) -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
103103
static Microsoft.Extensions.DependencyInjection.CascadingValueServiceCollectionExtensions.AddCascadingValue<TValue>(this Microsoft.Extensions.DependencyInjection.IServiceCollection! serviceCollection, System.Func<System.IServiceProvider!, TValue>! valueFactory) -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
104+
virtual Microsoft.AspNetCore.Components.NavigationManager.Refresh(bool forceReload = false) -> void
104105
virtual Microsoft.AspNetCore.Components.Rendering.ComponentState.DisposeAsync() -> System.Threading.Tasks.ValueTask
105106
virtual Microsoft.AspNetCore.Components.RenderTree.Renderer.AddPendingTask(Microsoft.AspNetCore.Components.Rendering.ComponentState? componentState, System.Threading.Tasks.Task! task) -> void
106107
virtual Microsoft.AspNetCore.Components.RenderTree.Renderer.CreateComponentState(int componentId, Microsoft.AspNetCore.Components.IComponent! component, Microsoft.AspNetCore.Components.Rendering.ComponentState? parentComponentState) -> Microsoft.AspNetCore.Components.Rendering.ComponentState!

src/Components/Server/src/Circuits/RemoteNavigationManager.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,25 @@ async Task PerformNavigationAsync()
117117
}
118118
}
119119

120+
/// <inheritdoc />
121+
public override void Refresh(bool forceReload = false)
122+
{
123+
_ = RefreshAsync();
124+
125+
async Task RefreshAsync()
126+
{
127+
try
128+
{
129+
await _jsRuntime.InvokeVoidAsync(Interop.Refresh, forceReload);
130+
}
131+
catch (Exception ex)
132+
{
133+
Log.RefreshFailed(_logger, ex);
134+
UnhandledException?.Invoke(this, ex);
135+
}
136+
}
137+
}
138+
120139
protected override void HandleLocationChangingHandlerException(Exception ex, LocationChangingContext context)
121140
{
122141
Log.NavigationFailed(_logger, context.TargetLocation, ex);
@@ -162,5 +181,8 @@ public static void RequestingNavigation(ILogger logger, string uri, NavigationOp
162181

163182
[LoggerMessage(4, LogLevel.Error, "Navigation failed when changing the location to {Uri}", EventName = "NavigationFailed")]
164183
public static partial void NavigationFailed(ILogger logger, string uri, Exception exception);
184+
185+
[LoggerMessage(5, LogLevel.Error, "Failed to refresh", EventName = "RefreshFailed")]
186+
public static partial void RefreshFailed(ILogger logger, Exception exception);
165187
}
166188
}

src/Components/Shared/src/BrowserNavigationManagerInterop.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ internal static class BrowserNavigationManagerInterop
1616

1717
public const string NavigateTo = Prefix + "navigateTo";
1818

19+
public const string Refresh = Prefix + "refresh";
20+
1921
public const string SetHasLocationChangingListeners = Prefix + "setHasLocationChangingListeners";
2022

2123
public const string ScrollToElement = Prefix + "scrollToElement";

src/Components/Web.JS/dist/Release/blazor.server.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Components/Web.JS/dist/Release/blazor.web.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Components/Web.JS/dist/Release/blazor.webview.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Components/Web.JS/src/Platform/WebView/WebViewIpcReceiver.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ export function startIpcReceiver(): void {
4141

4242
'Navigate': navigationManagerFunctions.navigateTo,
4343

44+
'Refresh': navigationManagerFunctions.refresh,
45+
4446
'SetHasLocationChangingListeners': navigationManagerFunctions.setHasLocationChangingListeners,
4547

4648
'EndLocationChanging': navigationManagerFunctions.endLocationChanging,

src/Components/Web.JS/src/Services/NavigationEnhancement.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ export function attachProgressivelyEnhancedNavigationListener(callbacks: Navigat
4848
document.addEventListener('click', onDocumentClick);
4949
document.addEventListener('submit', onDocumentSubmit);
5050
window.addEventListener('popstate', onPopState);
51+
52+
attachProgrammaticEnhancedNavigationHandler(performProgrammaticEnhancedNavigation);
5153
}
5254

5355
export function detachProgressivelyEnhancedNavigationListener() {
@@ -57,10 +59,6 @@ export function detachProgressivelyEnhancedNavigationListener() {
5759
}
5860

5961
function performProgrammaticEnhancedNavigation(absoluteInternalHref: string, replace: boolean) {
60-
if (hasInteractiveRouter()) {
61-
return;
62-
}
63-
6462
if (replace) {
6563
history.replaceState(null, /* ignored title */ '', absoluteInternalHref);
6664
} else {
@@ -70,8 +68,6 @@ function performProgrammaticEnhancedNavigation(absoluteInternalHref: string, rep
7068
performEnhancedPageLoad(absoluteInternalHref);
7169
}
7270

73-
attachProgrammaticEnhancedNavigationHandler(performProgrammaticEnhancedNavigation);
74-
7571
function onDocumentClick(event: MouseEvent) {
7672
if (hasInteractiveRouter()) {
7773
return;

src/Components/Web.JS/src/Services/NavigationManager.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export const internalFunctions = {
2525
setHasLocationChangingListeners,
2626
endLocationChanging,
2727
navigateTo: navigateToFromDotNet,
28+
refresh,
2829
getBaseURI: (): string => document.baseURI,
2930
getLocationHref: (): string => location.href,
3031
scrollToElement,
@@ -93,6 +94,14 @@ function performScrollToElementOnTheSamePage(absoluteHref : string, replace: boo
9394
scrollToElement(identifier);
9495
}
9596

97+
function refresh(forceReload: boolean): void {
98+
if (!forceReload && hasProgrammaticEnhancedNavigationHandler()) {
99+
performProgrammaticEnhancedNavigation(location.href, /* replace */ true);
100+
} else {
101+
location.reload();
102+
}
103+
}
104+
96105
// For back-compat, we need to accept multiple overloads
97106
export function navigateTo(uri: string, options: NavigationOptions): void;
98107
export function navigateTo(uri: string, forceLoad: boolean): void;

0 commit comments

Comments
 (0)