This question has been asked many times over the last few years, but all answers appear to either:
Within the ASP.NET Framework it was easy to return a 404 status. This could be intercepted by IIS or returned as a bespoke page. It didn't matter what level in the control/business logic hierarchy this occurred at:
if (myThing == null) {
var ctx = HttpContext.Current;
ctx.Response.Clear();
ctx.Response.StatusCode = System.Net.HttpStatusCode.NotFound;
ctx.Response.StatusDescription = "No data was found against that URL.";
ctx.Response.End();
}
if (myThing == null) {
ViewBag.ErrorMessage = "No data was found against that URL.";
Response.StatusCode = (int)HttpStatusCode.NotFound;
return View("~/Views/Error/NotFound.cshtml");
}
if (myThing == null) {
return NotFound();
}
Is there an equivalent within a Blazor Component (.razor file) when that component is configured to act as a @page (not a component placed inside a .cshtml file)?
I appreciate from the comments that the page is found and is processing the request, but to a search engine two similar URL's with different ID parameters are indexed as different pages.
A use case example would be this:
@page "/Product/{Id:int}"
@using Microsoft.EntityFrameworkCore
<h1>Product Details</h1>
@code {
[Inject]
IDbContextFactory<MyDbContext> _dbContextFactory { get; set; } = default!;
[Parameter]
public int? Id { get; set; }
protected override async Task OnInitializedAsync()
{
using var context = _dbContextFactory.CreateDbContext();
var thingToEdit = await context.MyEntities
.Where(e => e.EntityId == Id.Value)
.FirstOrDefaultAsync();
if (thingToEdit == null)
{
// Go to/show a 404 page/message, but must set HTTP status code header
}
else
{
// Show product details in this component page
}
}
}
Credit: How to replace Blazor default "soft 404" with an actual 404 status code response
I just added a Razor component called PageNotFound:
@using Microsoft.AspNetCore.Http
@using Tuneality.Web.Server.Views.Layout
@inject IHttpContextAccessor HttpContextAccessor
<PageTitle>Not Found</PageTitle>
<LayoutView Layout="@typeof(MainLayout)">
@ChildContent
</LayoutView>
@code {
[Parameter]
public RenderFragment ChildContent { get; set; }
protected override void OnInitialized() {
if (HttpContextAccessor.HttpContext != null)
HttpContextAccessor.HttpContext.Response.StatusCode = 404;
}
}
Then I changed my <NotFound> route to point at the component:
<Router AppAssembly="@typeof(ServerApp).Assembly">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)"/>
<FocusOnNavigate RouteData="@routeData" Selector="h1"/>
</Found>
<NotFound>
<PageNotFound>
There's nothing on this page!
</PageNotFound>
</NotFound>
</Router>
The result is a hard 404 status code on pages which are "not found." As was said in the comments by the OP, this is important for SEO reasons. It allows us to tell search engines to stop indexing the page if they had previously done so, so that we are able to remove content from the site when needed (among other things).
Since the new component accepts children to be rendered, you can use it as a generic component elsewhere with custom "not found" messages. For example, you could have a @page "/images/{id?}" component, and if the image were deleted, render the <PageNotFound> with a message like The image #{id} has been deleted.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With