Reputation: 1992
In my .NET 7 web site, I've set up the processing pipeline to use UseStatusCodePagesWithReExecute
but with a registered middleware in the pipeline returns 404, it correctly returns the 404.cshtml page, but it doesn't seem to reprocess the entire pipeline.
For example, I have a need to render a 404.cshtml page, but I have to change the response.StatusCode = 400
instead of 404
.
During the pipeline construction, I do this:
app
.Use( async ( context, next ) => {
if ( new[] { 500, 401, 403, 404 }.Contains( context.Response.StatusCode ) )
{
Console.WriteLine( $"app.Use (before) StatusCode: {context.Response.StatusCode}, {context.Request.Path}" );
}
await next();
} )
.UseExceptionHandler( "/errors/handler" )
.UseStatusCodePagesWithReExecute( "/errors/{0}" );
// register more middlewares, one which could return 404, psuedo is below...
app.Use( async ( context, next ) =>
{
if ( context.Request.Path.StartsWithSegments( "/app/channel-homex" ) )
{
context.Response.StatusCode = 404;
return;
}
await next();
} ).Use( async ( context, next ) =>
{
if ( new[] { 500, 401, 403, 404 }.Contains( context.Response.StatusCode ) )
{
Console.WriteLine( $"app.Use (after) StatusCode: {context.Response.StatusCode}, {context.Request.Path}" );
}
await next();
} );
As I understand it, when I do context.Response.StatusCode = 404; return;
it is supposed to start the pipeline over, however, I only get the 'after' output in the console instead of both the 'before' and the 'after'.
Am I misunderstanding pipelines or how to process return
vs await next()
in my middleware implementations?
UPDATE
I've made a copy an paste .NET7 Program.cs for debugging based on answer below, however it seems there are two important points I was missing.
UseStatusCodePagesWithReExecute
, that is the 'restart' point of the pipeline.StatusCode = 400
the browser still reports a return status of 404
(even though the console reports 400
).I think my only remaining question is the mystery about return
vs await next()
after setting status to 400. What is proper code to use?
var app = WebApplication.CreateBuilder( args ).Build();
app
.UseHttpsRedirection()
// Whereever this is registered is the 'restart' point for the pipeline
.UseStatusCodePagesWithReExecute( "/error/{0}" )
.Use( async ( context, next ) =>
{
Console.WriteLine( $"app.Use (before) StatusCode: {context.Response.StatusCode}, {context.Request.Path}" );
await next();
} )
// If registered here, this is where pipeline 'restarts' so I don't get 'before' log
// .UseStatusCodePagesWithReExecute( "/error/{0}" )
.Use( async ( context, next ) =>
{
if ( new[] { 500, 401, 403, 404 }.Contains( context.Response.StatusCode ) )
{
Console.WriteLine( $"app.Use change StatusCode=400: Current={context.Response.StatusCode}, {context.Request.Path}" );
context.Response.StatusCode = 400;
// If I don't return here, browser status is reported as 404 still
// return;
}
await next();
} )
.Use( async ( context, next ) =>
{
if ( context.Request.Path.StartsWithSegments( "/throw" ) )
{
Console.WriteLine( $"app.Use change StatusCode=404: Current={context.Response.StatusCode}, {context.Request.Path}" );
context.Response.StatusCode = 404;
return;
}
await next();
} )
.Use( async ( context, next ) =>
{
Console.WriteLine( $"app.Use (after) StatusCode: {context.Response.StatusCode}, {context.Request.Path}" );
await next();
} );
app.Run();
Upvotes: 0
Views: 57
Reputation: 28267
The reason why you just see the after is you use the UseStatusCodePagesWithReExecute
this method re-execute the request with the new path instead
I suggest you modify your middleware as below and test again:
app.UseStatusCodePagesWithReExecute("/errors/{0}");
app.Use(async (context, next) =>
{
await next();
if (new[] { 500, 401, 403, 404 }.Contains(context.Response.StatusCode))
{
Console.WriteLine($"app.Use (before) StatusCode: {context.Response.StatusCode}, {context.Request.Path}");
}
});
app.Use(async (context, next) =>
{
if (context.Request.Path.StartsWithSegments("/app/channel-homex"))
{
context.Response.StatusCode = 404;
await next();
}
else
{
await next();
}
});
app.Use(async (context, next) =>
{
await next();
if (new[] { 500, 401, 403, 404 }.Contains(context.Response.StatusCode))
{
Console.WriteLine($"app.Use (after) StatusCode: {context.Response.StatusCode}, {context.Request.Path}");
}
});
app.UseExceptionHandler("/errors/handler");
Result:
Upvotes: 0