dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.45k stars 10.03k forks source link

Create simpler way to show Not Found 404 UI with Blazor #45654

Open Alerinos opened 1 year ago

Alerinos commented 1 year ago

Is there an existing issue for this?

Is your feature request related to a problem? Please describe the problem.

Currently, we support the lack of a page in blazor, unfortunately, if we want to place a 404 header for SEO and, for example, google bot, it creates a problem. It's worth handling this exception. There is currently a workaround that doesn't look very good to me.

App.razor

        <NotFound>
            <PageTitle>Not found</PageTitle>
            <LayoutView Layout="@typeof(Pages._404)">
                404
            </LayoutView>
        </NotFound>

404 layout:

@layout Shared.MainLayout
@inherits LayoutComponentBase
@using Microsoft.AspNetCore.Http

@Body

@code {
    [Inject] IHttpContextAccessor httpContextAccessor { get; set; } = null!;

    [Inject] PersistentComponentState _ApplicationState { get; set; } = null!;

    PersistingComponentStateSubscription persistingSubscription;

    bool model = true;

    protected override void OnInitialized()
    {
        persistingSubscription = _ApplicationState.RegisterOnPersisting(Task () => { _ApplicationState.PersistAsJson($"404", model); return Task.CompletedTask; });
        if (!_ApplicationState.TryTakeFromJson<bool>($"404", out var dto))
        {
            if (httpContextAccessor.HttpContext is not null)
                httpContextAccessor.HttpContext.Response.StatusCode = StatusCodes.Status404NotFound;
        }
    }
}

Also I read in the documentation that we shouldn't use httpcontext in blazor subpages.

Describe the solution you'd like

I think Not Found blazor server side should automatically handle and ship. I've searched the internet and the documentation and found nothing useful.

Additional context

No response

ghost commented 1 year ago

Thanks for contacting us.

We're moving this issue to the .NET 8 Planning milestone for future evaluation / consideration. We would like to keep this around to collect more feedback, which can help us with prioritizing this work. We will re-evaluate this issue, during our next planning meeting(s). If we later determine, that the issue has no community involvement, or it's very rare and low-impact issue, we will close it - so that the team can focus on more important and high impact issues. To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.

Alerinos commented 1 year ago

@danroth27 I noticed that the new template (VS 17.8.0 Preview 2.0) lacks custom 404 error support.

danroth27 commented 1 year ago

@danroth27 I noticed that the new template (VS 17.8.0 Preview 2.0) lacks custom 404 error support.

Yes, this something we still expect to address in an upcoming .NET 8 update: https://github.com/dotnet/aspnetcore/pull/50550

danroth27 commented 1 year ago

@mkArtakMSFT Looks like we still have a functionality gap here that we need to discuss. #50550 didn't actually address this scenario. There was some related discussion in #48983 about having a way to trigger a 404 response, but that work wasn't done in https://github.com/dotnet/aspnetcore/pull/49801 either.

SteveSandersonMS commented 1 year ago

Could you clarify more about what doesn't work here? I just tried adding this to a page:

    [CascadingParameter] public HttpContext HttpContext { get; set; }

    protected override async Task OnInitializedAsync()
    {
        HttpContext.Response.StatusCode = 404;
    }

... and it worked immediately. It's also not necessary to add anything in <Router> because with SSR you already get a native ASP.NET Core 404 page if there's no matching .razor endpoint.

Alerinos commented 1 year ago

@SteveSandersonMS Before there was Blazor Web there was only Blazor Server Side, then the circuit worked the same way you would use it:

@attribute [RenderModeServer].

In this case, there were problems alone.

SteveSandersonMS commented 1 year ago

You certainly can't set a 404 status code, or any HTTP response headers, while in the middle of interactive rendering. At that time there is no HTTP response to set properties on, so it's not applicable as a concept.

But just to clarify, are you confirming this now works for you as you'd expect for SSR pages? Or are you saying that there is still a missing feature (and if so, what)?

Alerinos commented 1 year ago

@SteveSandersonMS Here you have a case where a 404 should be returned, what if the page will be rendered in RenderModeServer?

https://github.com/danroth27/BlazorScaffolding/blob/9a6cc450c4dbb144523a1081d9f987ecf668a87a/Components/Pages/Movies/Edit.razor#L67

SteveSandersonMS commented 1 year ago

what if the page will be rendered in RenderModeServer?

During prerendering you can set a status code on the HttpContext.

However, once the component has actually become interactive, there is no HTTP response so it would be meaningless to even talk about status codes. When fully interactive, all that matters is what UI you display, so you would just need to show in the UI that the item doesn't exist (which you also need to do in the SSR/prerendering cases, since normal users don't see or care about HTTP status codes either).

ghost commented 1 year ago

Thanks for contacting us.

We're moving this issue to the .NET 9 Planning milestone for future evaluation / consideration. We would like to keep this around to collect more feedback, which can help us with prioritizing this work. We will re-evaluate this issue, during our next planning meeting(s). If we later determine, that the issue has no community involvement, or it's very rare and low-impact issue, we will close it - so that the team can focus on more important and high impact issues. To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.

danroth27 commented 11 months ago

If you have a Blazor page using static SSR and you want to return a 404 with a common UI, there isn't really a good way to do that right now. In the Blazor scaffolder we use a hack of navigating to a known non-existent page: NavigationManager.NavigateTo("/notfound"), but that changes the URL.

Alerinos commented 11 months ago

@danroth27 Redirecting the link to notfound will be tragic for seo and the site.

This solution should be a priority to make blazor fully valuable.

danroth27 commented 11 months ago

@Alerinos Can you clarify for me the impact on SEO? I'm not seeing that. We're talking about pages that don't exist and shouldn't be indexed, right?

Alerinos commented 11 months ago

@danroth27 If there is a URL link that is not supported on the site and it shows up on Google, for example, then the site must return a 404. Otherwise, Google will still index the site and return an error in the search console.

T-Smith45 commented 11 months ago

@danroth27 I found a workaround to show a 404 page with Blazor SSR. https://github.com/T-Smith45/Blazor-404-redirect. Not sure if it's a proper workaround but I'm hoping some comments can be added to the default template since there's a lack of documentation on this issue. @Alerinos not sure if this works for your use case.

ghost commented 10 months ago

Thanks for contacting us.

We're moving this issue to the .NET 9 Planning milestone for future evaluation / consideration. We would like to keep this around to collect more feedback, which can help us with prioritizing this work. We will re-evaluate this issue, during our next planning meeting(s). If we later determine, that the issue has no community involvement, or it's very rare and low-impact issue, we will close it - so that the team can focus on more important and high impact issues. To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.

OrihuelaConde commented 6 months ago

@danroth27 I found a workaround to show a 404 page with Blazor SSR. https://github.com/T-Smith45/Blazor-404-redirect. Not sure if it's a proper workaround but I'm hoping some comments can be added to the default template since there's a lack of documentation on this issue. @Alerinos not sure if this works for your use case.

This is a good solution, but it does not provide enhanced navigation. When using 'InteractiveWebAssemblyRenderMode,' it reloads the app and may cause a strange experience for the user. I partially solved the issue by setting 'RenderModeForPage' to 'null' when navigating to '/Error', but the app still reloads when navigating to any path that uses 'InteractiveWebAssemblyRenderMode'.

kejdajar commented 3 months ago

I have encountered this challenge in my app where I am using InteractiveWebAssemblyRenderMode(prerender: false).

I wasn't satisfied with the UseStatusCodePagesWithRedirects method because it triggers a full page refresh when a user navigates to a non-existent page through a link within the app.

To address this, I implemented a fallback page as follows: DemoApp.Client.Pages.NotFound.razor

@page "/{*route:nonfile}"
<PageTitle>404 Not Found</PageTitle>
<h1>404 Not Found</h1>
The page @Route was not found.
@code {
 [Parameter]
    public string? Route { get; set; }
}

This page serves as a fallback for invalid links within my app without triggering a full page refresh. However, for unknown URLs entered manually by the user, a full page refresh still occurs, which is expected behavior.

I believe this solution can be useful for someone facing a similar issue, although I'm not entirely sure if it is the correct approach.

erictor commented 3 months ago

@kejdajar thank you! This was the only sample code I was able to find that for Blazor Server .NET 8 will catch Route Not Found and allow the Route that wasn't found to be captured in a Parameter for inspection and potential additional logic. I checked now, and see that route:nonfile is discussed in .NET 8 documentation but not with sample code as provided above. It appears to me this is a gap in documentation - I didn't find a place where recommended practices for handling Not Found Routes in a common manner where logic can be applied and different responses can be invoked based on the Not Found Route. Microsoft, whatever is done in this realm for Blazor .NET 9 please don't render the above solution inoperable.