如何在 Razor Page OnInitialized 事件中使用 404 路由

Posted

技术标签:

【中文标题】如何在 Razor Page OnInitialized 事件中使用 404 路由【英文标题】:How to use 404 routing in Razor Page OnInitialized event 【发布时间】:2020-04-15 19:33:17 【问题描述】:

在服务器端 Blazor 应用程序 (Core 3.1) 中,有一个 Razor 接受 @page 属性中的标识符。如果 URL 中提供的标识符对应于现有实体,则页面将正常呈现。但是,如果标识符不是已知实体(由其在存储库中的存在确定),我希望系统执行与 404 Not Found 对应的任何操作。但是,在路由已经匹配并且我的页面的 OnInitialized() 正在执行之前,我不知道这一点。

在这种情况下如何“重定向”到默认的 404 处理。

页面如下所示:

@page "/projectname"

<!-- html Here -->

@code 


    [Parameter]
    public string ProjectName get; set;

    private UpdateProjectViewModel Project;

    protected override void OnInitialized()
    
        var project = Repository.Get(ProjectName);
        if (project == null)
        
            WANT TO USE 404 ROUTING HERE.
        
        Project = new UpdateProjectViewModel(project));
    


【问题讨论】:

通过@inject NavigationManager navMgrnavMgr.NavigateTo("/404",false); 注入一个NavigationManager ? 仅供参考,如果你沿着这条路线走,把它放在 AfterRender 方法中,否则 navimanager 会抛出异常 恐怕没有什么比 page.razor 文件中的简单 if/else 更好的了。我在页面顶部做了这样的事情:@if(_notFound) &lt;NotFoundComponent /&gt; return; 。 return 语句允许我跳过 else 块并防止嵌套在组件的其余部分中。 【参考方案1】:

如果您想在显示错误 404 的同时“保持”在同一条路线上:

创建一个类NotFoundListener.cs

public class NotFoundListener
    
        public  Action OnNotFound  get;set; 

        public void NotifyNotFound()
        
            if(NotifyNotFound != null)
            
                OnNotFound.Invoke();
            
        

    

将其作为作用域服务注入

builder.Services.AddScoped<NotFoundListener>();

在你的MainLayout.razor

@inherits LayoutComponentBase
@inject NotFoundListener nfl;

<PageTitle>ImportTesting</PageTitle>

<div class="page">
    <div class="sidebar">
        <NavMenu />
    </div>

    <main>
        <div class="top-row px-4">
            <a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
        </div>

        <article class="content px-4">
            @if (notFound)
            
                <h1>Could not find the content you are looking for</h1>
            else
            
                @Body
            
        </article>
    </main>
</div>


@code
    private bool notFound;

    protected override void OnInitialized() => nfl.OnNotFound += SetNotFound;

    void SetNotFound()
    
        notFound = true;
        StateHasChanged();
    


并且在你要引发 404 的页面中:

protected override void OnInitialized()

    if (project == null)
    
        nfl.NotifyNotFound();
    

这将:

    让您在浏览器中保持同一路线 不导航到任何地方 确保每一页都没有 if else (我用Action来处理事件,不是最好的使用方式,但是让代码更容易阅读)

现在,

您可以为不同的页面设置不同的事件侦听器。 您可以根据具体需要创建不同的布局。 如果您只想在某些页面而不是所有页面上应用此功能,请添加 'route' 事件的参数并在 MainLayout 上检查它。

如果您想重复使用标准错误页面:

您的错误页面在您的 App.razor 中定义

<Router AppAssembly="@typeof(App).Assembly">
    <Found Context="routeData">
        <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
        <FocusOnNavigate RouteData="@routeData" Selector="h1" />
    </Found>
    <NotFound>
        <PageTitle>Not found</PageTitle>
        <LayoutView Layout="@typeof(MainLayout)">
            <p role="alert">Sorry, there's nothing at this address.</p>
        </LayoutView>
    </NotFound>
</Router>

您可以创建自己的NotFoundComponent.razor 组件

<PageTitle>Not found</PageTitle>
<LayoutView Layout="@typeof(MainLayout)">
    <p role="alert">Sorry, there's nothing at this address.</p>
</LayoutView>

您更新后的App.razor 如下所示:

<Router AppAssembly="@typeof(App).Assembly">
    <Found Context="routeData">
        <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
        <FocusOnNavigate RouteData="@routeData" Selector="h1" />
    </Found>
    <NotFound>
       <NotFoundComponent/>
    </NotFound>
</Router>

然后你可以创建一个简单地引用同一个组件的页面

NotFoundPage.razor

@page "/NotFound"

<NotFoundComponent />

然后使用您的页面重定向如下

来自您的 OnInitialized()

    @page "/projectname"
    
    <!-- HTML Here -->
    
    @code 


    [Parameter]
    public string ProjectName get; set;

    private UpdateProjectViewModel Project;

    protected override void OnInitialized()
    
        var project = Repository.Get(ProjectName);
        if (project == null)
        
            NavigationManager.NavigateTo("/NotFound");        
        
        Project = new UpdateProjectViewModel(project));
    

【讨论】:

感谢您的尝试,但我想显示路由不匹配时已经显示的标准 404 错误。我不想重新发明在我想要这样做的每个页面中显示的 404 页面,也不想将 html 部分与分支逻辑混淆。 你的意思是浏览器显示的页面?如果是,您想在地址栏中看到什么? 更新了我的答案,请检查是否是您需要的。 正确,但这仍然会重定向用户。请参阅罗斯 P 在另一个答案中的评论,“使用这种方法,您不会以“/404”结束吗?“未找到响应”不应导致重定向到另一个页面,而是将用户保留在内容可能的 url找不到。” 更新了答案。我已经测试过了。【参考方案2】:

这里是代码sn-p

@page "/navigate"
@inject NavigationManager NavigationManager

<h1>Navigate in Code Example</h1>

<button class="btn btn-primary" @onclick="NavigateToCounterComponent">
    Navigate to the Counter component
</button>

@code 
    private void NavigateToCounterComponent()
    
        NavigationManager.NavigateTo("404");
    

【讨论】:

使用此解决方案,可能应用程序认为我正在尝试导航到名为 404 的 项目,然后重定向到 404 并生成太多重定向错误。我假设“404”字符串没有特殊含义,只会根据我设置的任何路由进行路由——我需要使用一些保证不会被我的应用程序处理的东西? 您需要放置一个组件来代替 404。这里是您可以获得帮助的链接:docs.microsoft.com/en-us/aspnet/core/blazor/… @RafaqatAli,使用这种方法,您不会以“/404”结尾吗? “未找到响应”不应导致重定向到另一个页面,而是将用户留在无法找到内容的 url。 你找到这个@RossP 的解决方案了吗?我同意你的看法,这个答案不是解决方案,也不是“正确”的 404。

以上是关于如何在 Razor Page OnInitialized 事件中使用 404 路由的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 ASP.NET Core 同时制作 Razor Page 和 C# 代码框架?

Razor Page中的AJAX

JSON.stringify 作为 Null 传入 Razor-Page

ASP.NET Core Razor Pages 强制 Anchor Tag Helper (asp-page) 使用小写路由

如何在 Blazor 中创建 Razor 页面列表

Razor:asp-page-handler 不会触发处理程序并抛出 400 错误