从 Blazor 组件(.razor) 重定向到 Razor 页面(.cshtml) [服务器端]

3

这是我的使用案例。我有一个单例对象,它保存着全局站点状态。我的网站上有一个按钮,当点击时会在全局站点状态对象上触发一个事件。我有一个 Blazor 组件(razor),它正在监听此事件。它响应该事件并执行以下操作:

var path = "siteupdate".AddInitialQueryStringArg("returnUrl", _navManager.Uri);
_navManager.NavigateTo(path,true);

所有在线用户都会被重定向到一个Razor页面(.cshtml),该页面上会显示一条消息,提示"网站正在更新中,请稍后再来访问"。这是为了在服务器暂时关闭或更新并且与SignalR hub失去连接时,提供良好的用户体验所必需的要求。
执行后,似乎浏览器尝试导航到siteupdate页面,但最终被拒绝,并在我发出调用时返回到当前组件。类似于手动更新浏览器中的URL时,导航管理器会将其重置。通过在我的Razor Page 中设置断点,我可以确定大多数时间都会调用OnGet方法,但似乎没有得到响应或其他什么问题? 我已经尝试了以下操作:
尝试通过JavaScript设置窗口位置

var path = "/update".AddInitialQueryStringArg("returnUrl", _navManager.Uri);
JSRuntime.InvokeVoidAsync("BlazorHelpers.RedirectTo", path);

试图避免使用强制重新加载,这将导致404错误。

var path = "/siteupdate".AddInitialQueryStringArg("returnUrl", _navManager.Uri);
_navManager.NavigateTo(path);

参考代码位于 Pages/SiteUpdate/UpdateLandingPage.cshtml 下。 我尝试将它放在 Pages 文件夹下,但正如我之前所说的,OnGet 方法被调用了,所以路由器似乎找到了它,但是框架似乎以某种方式覆盖了 URL。谢谢。

你能否从一个全新的浏览器窗口访问siteupdate页面?如果不能,检查你的路由/端点配置。 - Mister Magoo
好问题,是的,如果我打开一个新标签并手动输入地址,它就可以正常工作。 - George Fabish
你有在浏览器开发工具的网络选项卡中监控浏览器请求,以查看正在发生的请求/响应吗? - Mister Magoo
我遇到了一个奇怪的问题,就是当上一页重新加载时,会出现一个“blocked”或其他东西,它会立即消失。我认为@Quarango在这种情况下对于Blazor组件(.razor)和Razor页面(.cshtml)之间的导航有一些见解,这可能会更加复杂。 - George Fabish
你可以在浏览器开发工具中勾选一个框(在Edge中称为“保留日志”),以保留历史记录,这样就不会丢失捕获的请求 - 你需要看到正在发生的事情 - 听起来像是站点更新页面立即重定向,但你可以通过捕获响应来确认。 - Mister Magoo
1个回答

1
你的问题有两个部分:一个是所有用户都能看到的常见更新服务,另一个是在更新发生时用户所在的个人页面,该页面设置了重定向。这些需要使用SingletonScoped上下文分别实现。
我通过创建两个服务来测试这个问题:
UpdateService.cs
    /// <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();
        }
    }

这里有一个事件OnUpdate,当更新发生时,消费者可以订阅它。
RedirectService.cs
    /// <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;
        }
    }

这项服务使用UpdateService并监听OnUpdate事件。如果当前URL不是“/siteupdate”,则会将用户重定向。
Startup.cs中注册这两个服务。
// a singleton service - all users share this
services.AddSingleton<UpdateService>();
// scoped service for the redirect
services.AddScoped<RedirectService>();

顺序很重要,因为 RedirectService 需要 UpdateService
为了触发此操作,我只需在 MainLayout.razor 中注入服务即可:
@inherits LayoutComponentBase
@inject Data.RedirectService redirectService

为了测试这个功能,我在 Index.razor 上放了一个按钮,当用户点击后,该用户和其他在不同页面/浏览器上的用户都会重定向到新页面。
这意味着除了 /siteupdate 页面外的任何页面上的任何用户都将被重定向。如果这不是您的用例(例如,只有某些页面/用户应该重定向),则可以相应地进行调整。

您的项目中的siteupdate端点是razor页面还是blazor组件?我仍然得到与之前相同的结果,如果我尝试在没有强制重新加载参数的情况下导航,则nav管理器似乎期望端点是blazor组件,因此返回页面未找到。使用强制重新加载,它会命中正确的页面,但会以某种方式重置回原始页面。 - George Fabish
SiteUpdate 是一个 Blazor 页面:SiteUpdate.razor,在开头有一个 @page "/siteupdate" 路由。这种技术只适用于 Blazor 页面 - 如果您想重定向 Razor Pages(即 .cshtml),则需要使用一些基于 JS 的系统,如 SignalR 等推送技术。那会更加复杂。 - Quango
@GeorgeFabish 我可以澄清一下吗:您是否正在尝试在 Razor 页面(.cshtml)中使用 NavigationManagerNavigationManager 是 Blazor 路由服务,不适用于 cshtml。 - Quango
你能给我一些指导,告诉我在哪里查看如何实现JS互操作来处理这个问题吗? - George Fabish
1
不行 - 因为JSinterop是Blazor的一部分,而Blazor不能运行.. 所以它也就无法工作了。你需要完全不同的解决方案。 - Quango
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接