Reputation: 1101
I've been having problems with UseStatusCodePagesWithReExecute
in a dotnet razor pages web app whilst attempting to show a custom 404 error page for page requests that return a NotFound result. Specifically, if I return a NotFound from an OnGet method I find the same request is called again and there's never a re-execution of the path supplied to the middleware.
I'm using .NET Core 3.0 so haven't tried with previous versions, or the 3.1 previews.
I've managed to replicate the problem with a simple repro. The following will allow an invalid route to redirect to the error page (e.g. https://localhost:5001/foo
), however, the route https://localhost:5001/
will get called twice and not redirect to the error page.
So the question I'm asking, is this a bug or am I missing some concept here? I've tried the related UseStatusCodePagesWithRedirects
method and that does what it says it should do but I'd really like to use the ReExecute if I can.
Repro
Environment:
Steps:
dotnet new webapp -n myapp
.Index.cshtml.cs
OnGet
method to be the following: public IActionResult OnGet()
{
return NotFound();
}
Startup.cs
and add app.UseStatusCodePagesWithReExecute("/Error");
just after the if/else code block in the Configure method, like so: public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
// Added this line
app.UseStatusCodePagesWithReExecute("/Error");
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
/Error
doesn't occur and instead the breakpoint is hit again.Thanks in advance.
Upvotes: 6
Views: 3174
Reputation: 282
StatusCodePages middleware has 3 methods to show custom error pages, they are
UseStatusCodePages
, UseStatusCodePagesWithRedirects
and UseStatusCodePagesWithReExecute
. If you want to return a NotFound
result whenever you visit https://localhost:5001/ by editing Index.cshtml.cs
OnGet
method, you should use UseStatusCodePages
to customize your 404 error page rather than UseStatusCodePagesWithReExecute
.
Nevertheless, if you persist in using UseStatusCodePagesWithReExecute
, you don't need to return a real NotFound
. UseStatusCodePagesWithReExecute
is for non-existing resources. Once you visit https://localhost:5001/any-non-exisisting-page, it will throw 404 and then re-execute a request for your own error page. But it's not a replacement of NotFound
method. At the same time, pay attention to some conditions and restriction when using UseStatusCodePagesWithReExecute
, you can refer to this article: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/error-handling?view=aspnetcore-3.1 .
Here's a working sample.
Edit Startup.cs Configure method, like so:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
//app.UseDeveloperExceptionPage();
}
else
{
// app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for
production scenarios, see https://aka.ms/aspnetcore-hsts.
// app.UseHsts();
}
//app.UseStatusCodePages();
app.UseStatusCodePagesWithReExecute("/Error", "?code={0}");
// app.UseHttpsRedirection();
app.UseStaticFiles();
//app.UseStatusCodePagesWithRedirects("/Error");
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
Add @page "{code?}" to Error.cshtml:
@page "{code?}"
@model ErrorModel
@{
ViewData["Title"] = "Error";
}
<h1 class="text-danger">Error.</h1>
<h1 class="text-danger">Status Code: @Model.ErrorStatusCode</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>
@if (Model.ShowRequestId)
{
<p>
<strong>Request ID:</strong> <code>@Model.RequestId</code>
</p>
}
<h3>Development Mode</h3>
<p>
Swapping to the <strong>Development</strong> environment displays detailed information about the error that occurred.
</p>
<p>
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
It can result in displaying sensitive information from exceptions to end users.
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
and restarting the app.
</p>
Upvotes: 4
Reputation: 1673
If you use
return new NotFoundResult();
instead of
return NotFound();
it will use the desired pipeline, only downside is there is no way to pass a message, if you want to pass a message, then you need to build you own middleware to handle that situation.
Upvotes: 2