-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Description
Describe the bug
app.UseStatusCodePagesWithReExecute(string pathFormat) must come before any explicit call to app.UseRouting() in order to redo route matching with pathFormat. Reversing this order causes requests that should result in a status code page to result in a 404 instead because the route matching is never rerun.
The problem is that correctly putting UseStatusCodePagesWithReExecute before UseRouting causes [SkipStatusCodePages] to be ignored. StatusCodePagesMiddlewarechecks for ISkipStatusCodePagesMetadata before UseRouting sets the metadata. (One possible fix might be to check for the metadata again after calling _next if GetEndpoint() returned null before calling _next.)
public void Configure(IApplicationBuilder app)
{
app.UseStatusCodePagesWithReExecute("/status");
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", () =>
{
return Results.BadRequest(); // "Status: 400" correctly written to body
});
endpoints.MapGet("/skip", [SkipStatusCodePages] () =>
{
return Results.BadRequest(); // "Status: 400" *incorrectly* written to body
});
endpoints.MapGet("/status", (HttpResponse response) =>
{
return $"Status: {response.StatusCode}"; // "Status: 200" correctly written to body when hit directly
});
});
}Reversing the order leads to 404s. This is unfortunately by design, but it would be great if we could make this work similar to the way we do for the implicit UseRouting in WebApplication.
public void Configure(IApplicationBuilder app)
{
app.UseRouting();
app.UseStatusCodePagesWithReExecute("/status");
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", () =>
{
return Results.BadRequest(); // Empty 404 response
});
endpoints.MapGet("/skip", [SkipStatusCodePages] () =>
{
return Results.BadRequest(); // Empty 404 response
});
endpoints.MapGet("/status", (HttpResponse response) =>
{
return $"Status: {response.StatusCode}"; // "Status: 200" correctly written to body when hit directly
});
});
}If WebApplication is used instead with its implicit call to UseRouting, everything works correctly. Rerouting does not 404 and [SkipStatusCodePages] is respected. This is thanks to @BrennanConroy's work in #35426. Maybe we could do something similar for non-WebApplication scenarios.
using Microsoft.AspNetCore.Mvc;
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseStatusCodePagesWithReExecute("/status");
// Adding app.UseRouting() here would reintroduce the broken behavior of ignoring [SkipStatusCodePages]
app.MapGet("/", () =>
{
return Results.BadRequest(); // "Status: 400" correctly written to body
});
app.MapGet("/skip", [SkipStatusCodePages] () =>
{
return Results.BadRequest(); // Correct empty 400 response because /status is skipped
});
app.MapGet("/status", (HttpResponse response) =>
{
return $"Status: {response.StatusCode}"; // "Status: 200" correctly written to body when hit directly
});
app.Run();More context from previous work in this area: #38509 (comment)
Expected Behavior
[SkipStatusCodePages] should be respected and rerouting should not 404.
public void Configure(IApplicationBuilder app)
{
app.UseStatusCodePagesWithReExecute("/status");
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", () =>
{
return Results.BadRequest(); // "Status: 400" correctly written to body
});
endpoints.MapGet("/skip", [SkipStatusCodePages] () =>
{
return Results.BadRequest(); // Correct empty 400 response because /status is skipped
});
endpoints.MapGet("/status", (HttpResponse response) =>
{
return $"Status: {response.StatusCode}"; // "Status: 200" correctly written to body when hit directly
});
});
}.NET Version
7.0.100-alpha.1.22060.1