Reputation: 131
I've been trying to use the UseStatusCodePagesWithReExecute
method to show a page that shows customized messages per status code on the application I'm trying to make with ASP.NET Core 3.0
I've followed the instructions on this website, but right now, if I try to test this by accessing a non-existant webpage, a blank page shows up, and the code doesn't pass through the OnGet
method on the Razor Page I want to be shown (I used breakpoints).
However, I am able to get the status page to show by accessing manually the page on my browser using the /Status/404
URI.
On the startup file, I've added the required lines, as shown in the tutorial.
// Startup.cs
public static void Configure(IApplicationBuilder app,
IWebHostEnvironment env,
IHostApplicationLifetime appLifetime)
{
app.UseDeveloperExceptionPage();
app.UseStatusCodePagesWithReExecute("/Status/{0}");
app.UseExceptionHandler("/Status");
// Irrelevant code below
}
The status model contains a OnGet
method that takes the code number as a parameter
// Status.cshtml.cs
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public class StatusModel : PageModel
{
public void OnGet(string? code = null)
{
if (null == code)
code = HttpContext.Response.StatusCode.ToString();
PageTitle = $"HTTP status {code}";
StatusNumber = code;
if (code.CompareTo("404") == 0)
{
StatusName = "Not found";
StatusDescription = "The requested page was not found.";
}
else
{
StatusName = "Unknown error";
StatusDescription = "An unknown error occurred.";
}
}
}
The status view is quite simple:
@page "{code?}"
@model StatusModel
@{
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>@Model.PageTitle</title>
</head>
<body>
<div>
<h1>@Model.StatusNumber</h1>
<h2>@Model.StatusName</h2>
<h2>@Model.StatusDescription</h2>
</div>
<p>RID: @Model.RequestId</p>
</body>
</html>
On the output console, I can see that indeed the application noticed that it caught the 404, but it doesn't appear to do anything:
info: Microsoft.AspNetCore.Mvc.StatusCodeResult[1]
Executing HttpStatusCodeResult, setting HTTP status code 404
info: Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker[4]
Executed page /Index in 225.4469ms
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
Executed endpoint '/Index'
Is there something that's changed when passing from ASP.NET Core 2.2 to 3.0 that I forgot to edit / add to make this work, or is this already supposed to work?
Upvotes: 2
Views: 1601
Reputation: 36655
Is there something that's changed when passing from ASP.NET Core 2.2 to 3.0 that I forgot to edit / add to make this work, or is this already supposed to work?
This is already supposed to work.
Status.cshtml:
@page "{code?}"
@model StatusModel
@{
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>@Model.PageTitle</title>
</head>
<body>
<div>
<h1>@Model.StatusNumber</h1>
<h2>@Model.StatusName</h2>
<h2>@Model.StatusDescription</h2>
</div>
</body>
</html>
Status.cshtml.cs:
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public class StatusModel : PageModel
{
public string PageTitle { get; set; }
public string StatusNumber { get; set; }
public string StatusName { get; set; }
public string StatusDescription { get; set; }
public void OnGet(string? code = null)
{
if (null == code)
code = HttpContext.Response.StatusCode.ToString();
PageTitle = $"HTTP status {code}";
StatusNumber = code;
if (code.CompareTo("404") == 0)
{
StatusName = "Not found";
StatusDescription = "The requested page was not found.";
}
else
{
StatusName = "Unknown error";
StatusDescription = "An unknown error occurred.";
}
}
}
Update:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseStatusCodePagesWithReExecute("/Status/{0}");
app.UseExceptionHandler("/Status");
}
else
{
app.UseDeveloperExceptionPage();
app.UseStatusCodePagesWithReExecute("/Status/{0}");
app.UseExceptionHandler("/Status");
// 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.Use(async (context, next) =>
{
await next();
if (context.Response.StatusCode == 401)
{
var newPath = new PathString("/Status/401");
var originalPath = context.Request.Path;
var originalQueryString = context.Request.QueryString;
context.Features.Set<IStatusCodeReExecuteFeature>(new StatusCodeReExecuteFeature()
{
OriginalPathBase = context.Request.PathBase.Value,
OriginalPath = originalPath.Value,
OriginalQueryString = originalQueryString.HasValue ? originalQueryString.Value : null,
});
// An endpoint may have already been set. Since we're going to re-invoke the middleware pipeline we need to reset
// the endpoint and route values to ensure things are re-calculated.
context.SetEndpoint(endpoint: null);
var routeValuesFeature = context.Features.Get<IRouteValuesFeature>();
routeValuesFeature?.RouteValues?.Clear();
context.Request.Path = newPath;
try
{
await next();
}
finally
{
context.Request.QueryString = originalQueryString;
context.Request.Path = originalPath;
context.Features.Set<IStatusCodeReExecuteFeature>(null);
}
// which policy failed? need to inform consumer which requirement was not met
//await next();
}
});
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
Upvotes: 3