Reputation: 439
Here's my use case. I have a singleton object that is holding global site state. I have a button on my website that when clicked fires an event on the global site state object. I have a Blazor component(razor) that is listening for this event. It responds to the event by doing this
var path = "siteupdate".AddInitialQueryStringArg("returnUrl", _navManager.Uri);
_navManager.NavigateTo(path,true);
The idea is that all online users are redirected to a Razor page(.cshtml) that has a message saying "The Website is being updated, come back later". This is a requirement to provide a decent user experience for when the server goes down temporarily for an update and loses connection to the SignalR hub.
Following the execution it appears as if the navigator tries to navigate to the siteupdate
page but it ends up getting rejected and resets back to whatever component I was on when I make the call. Similar to when you try to update the url in the browser manually and the navmanager resets it. Putting breakpoints in my Razor Page I can tell that the OnGet
method gets called most of the time, but it seems like it's response is not being acknowledge or something? I've tried the following :
Attempted to set window location via javascript
var path = "/update".AddInitialQueryStringArg("returnUrl", _navManager.Uri);
JSRuntime.InvokeVoidAsync("BlazorHelpers.RedirectTo", path);
Attempted to not use force reload, this results in a 404
var path = "/siteupdate".AddInitialQueryStringArg("returnUrl", _navManager.Uri);
_navManager.NavigateTo(path);
For reference I have the Razor page under
Pages/SiteUpdate/UpdateLandingPage.cshtml
I tried placing it just under the Pages folder, but like I said earlier the OnGet
method is getting called so the router seems to be finding it, but it seems like the framework is overwriting the URL somehow.
Thanks
Upvotes: 4
Views: 2928
Reputation: 13468
You have two parts to your problem: a common update service that all users see, and the individual page a user is on when the update occurs which sets the redirect. These would need Singleton
and Scoped
contexts respectively.
I tested this out creating two services:
/// <summary>
/// A singleton service that alerts users about updates
/// </summary>
public class UpdateService
{
/// <summary>
/// Event raised when an update starts
/// </summary>
public event Action OnUpdate;
public void TriggerUpdate()
{
// trigger the event
OnUpdate?.Invoke();
}
}
This has an event OnUpdate
that consumers can subscribe to when the update occurs.
/// <summary>
/// Redirect service (user-scoped)
/// </summary>
public class RedirectService : IDisposable
{
private readonly NavigationManager navigationManager;
private readonly UpdateService updateService;
public RedirectService(NavigationManager navigationManager,
UpdateService updateService)
{
this.navigationManager = navigationManager;
this.updateService = updateService;
// register for updates
this.updateService.OnUpdate += HandleUpdate;
}
private void HandleUpdate()
{
// get user's current URL
var uri = new Uri(navigationManager.Uri);
if (!uri.PathAndQuery.StartsWith("/siteupdate", StringComparison.CurrentCultureIgnoreCase))
{
// redirect
navigationManager.NavigateTo($"/siteupdate?redirectUrl={uri.PathAndQuery}");
}
}
// Cleanup
public void Dispose()
{
updateService.OnUpdate -= HandleUpdate;
}
}
This service consumes the UpdateService
and listens for OnUpdate
events. If the current URL isn't already "/siteupdate" it redirects the user.
In Startup.cs
you register these two services
// a singleton service - all users share this
services.AddSingleton<UpdateService>();
// scoped service for the redirect
services.AddScoped<RedirectService>();
The order is important since RedirectService
needs the UpdateService
.
To get this to trigger I just injected the service in MainLayout.razor
:
@inherits LayoutComponentBase
@inject Data.RedirectService redirectService
To test this I put a button on Index.razor
and when clicked that user and all other users on different pages/browsers all redirected to the new page.
That means that any user on any page except /siteupdate
will be redirected. If that's not your use-case (e.g. only some pages/users should redirect) you can adapt accordingly.
Upvotes: 1