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

Posted

技术标签:

【中文标题】从 Blazor 组件 (.razor) 重定向到 Razor 页面 (.cshtml) [服务器端]【英文标题】:Redirect from Blazor Component(.razor) to Razor Page(.cshtml) [ServerSide] 【发布时间】:2021-11-10 02:51:01 【问题描述】:

这是我的用例。我有一个持有全局站点状态的单例对象。我的网站上有一个按钮,单击该按钮会在全局站点状态对象上触发一个事件。我有一个正在侦听此事件的 Blazor 组件(剃刀)。它通过这样做来响应事件

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

这个想法是将所有在线用户重定向到 Razor 页面 (.cshtml),其中显示“网站正在更新,稍后再回来”的消息。当服务器因更新而暂时停机并失去与 SignalR 集线器的连接时,这是提供良好用户体验的必要条件。

在执行之后,它看起来好像导航器试图导航到 siteupdate 页面,但它最终被拒绝并重置回我拨打电话时所在的任何组件。类似于您尝试手动更新浏览器中的 url 并且 navmanager 将其重置。在我的 Razor 页面中放置断点我可以看出 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);

作为参考,我在下面有 Razor 页面 Pages/SiteUpdate/UpdateLandingPage.cshtml 我尝试将它放在 Pages 文件夹下,但正如我之前所说,OnGet 方法被调用,因此路由器似乎正在找到它,但似乎框架以某种方式覆盖了 URL。

谢谢

【问题讨论】:

您可以从新的浏览器窗口访问站点更新页面吗?如果没有,请检查您的路由/端点配置 好问题,是的,如果我打开一个新标签并手动输入地址,它就可以正常工作。 您是否在浏览器开发工具网络选项卡中监控了浏览器请求 - 查看正在发生的请求/响应? 我得到一个奇怪的“被阻止”或在重新加载前一页时立即消失的东西。我认为@Quarango 在 blazor 组件(.razor)和 razor 页面(.cshtml)之间的导航在这种情况下有点复杂。 您可以在浏览器开发工具中勾选一个框以保留历史记录(在 Edge 中称为“保留日志”),这样您就不会丢失捕获的请求 - 您需要查看发生了什么 - 这听起来像siteupdate 页面正在立即重定向,但您可以通过捕获响应来确认 【参考方案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 端点是剃刀页面还是 blazor 组件?仍然得到与以前相同的结果,如果我尝试在没有强制重新加载参数的情况下导航,导航管理器似乎期望端点是一个 blazor 组件,因此返回找不到页面。通过强制重新加载,它会访问正确的页面,但会以某种方式重置回原始页面。 SiteUpdate 是一个 Blazor 页面:SiteUpdate.razor,开头带有 @page "/siteupdate" 路由。此技术仅适用于 Blazor 页面 - 如果您还想重定向 Razor 页面(即.cshtml),则需要使用某种推送技术(如 SignalR)的基于 JS 的系统。这要复杂得多 @GeorgeFabish 我能否澄清一下:您是否尝试在 Razor 页面 (.cshtml) 中使用 NavigationManagerNavigationManager 是 Blazor 路由服务:不适用于 cshtml 正如标题所说,我想从 blazor 组件导航到 Razor 页面 .cshtml。抱歉,如果不够清楚。我不能只导航到另一个 blazor 组件的原因是,当网站因更新而脱机时,用户失去了他们的 SignalR 连接,因此登录页面在这种情况下对他们没有好处。 否 - 因为 JSinterop 将成为 Blazor 的一部分,它不起作用.. 所以它不起作用。你需要一个完全不同的解决方案

以上是关于从 Blazor 组件 (.razor) 重定向到 Razor 页面 (.cshtml) [服务器端]的主要内容,如果未能解决你的问题,请参考以下文章

如何将可操作的控制字符从 JSON 文本元素传递到 razor 组件 Blazor 变量

重定向到 Blazor WebAssembly 中的 403 禁止组件

C#:如何在 Blazor Wasm 托管中将动态 Razor 组件从服务器发送到客户端?

如何从服务器端 Blazor 应用程序中的 Blazor 组件调用 razor 页面而不导致页面刷新

从 Blazor 中的页面组件调用 MainLayout 中的方法

如何将 Font Awesome 添加到 Blazor 客户端(Razor 组件)应用程序?