Add an option to allow 404 responses from ExceptionHandlers (#26567)

This commit is contained in:
John Luo 2020-10-06 10:23:58 -07:00 committed by GitHub
parent d5b5f08a4f
commit 8555002772
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 64 additions and 1 deletions

View File

@ -132,7 +132,7 @@ namespace Microsoft.AspNetCore.Diagnostics
await _options.ExceptionHandler(context);
if (context.Response.StatusCode != StatusCodes.Status404NotFound)
if (context.Response.StatusCode != StatusCodes.Status404NotFound || _options.AllowStatusCode404Response)
{
if (_diagnosticListener.IsEnabled() && _diagnosticListener.IsEnabled("Microsoft.AspNetCore.Diagnostics.HandledException"))
{

View File

@ -22,5 +22,14 @@ namespace Microsoft.AspNetCore.Builder
/// explicitly provided, the subsequent middleware pipeline will be used by default.
/// </summary>
public RequestDelegate ExceptionHandler { get; set; }
/// <summary>
/// This value controls whether the <see cref="ExceptionHandlerMiddleware" /> should
/// consider a response with a 404 status code to be a valid result of executing the
/// <see cref="ExceptionHandler"/>. The default value is false and the middleware will
/// consider 404 status codes to be an error on the server and will therefore rethrow
/// the original exception.
/// </summary>
public bool AllowStatusCode404Response { get; set; }
}
}

View File

@ -542,5 +542,59 @@ namespace Microsoft.AspNetCore.Diagnostics
&& w.EventId == 4
&& w.Message == "No exception handler was found, rethrowing original exception.");
}
[Fact]
public async Task ExceptionHandler_CanReturn404Responses_WhenAllowed()
{
var sink = new TestSink(TestSink.EnableWithTypeName<ExceptionHandlerMiddleware>);
var loggerFactory = new TestLoggerFactory(sink, enabled: true);
using var host = new HostBuilder()
.ConfigureWebHost(webHostBuilder =>
{
webHostBuilder
.UseTestServer()
.ConfigureServices(services =>
{
services.AddSingleton<ILoggerFactory>(loggerFactory);
services.Configure<ExceptionHandlerOptions>(options =>
{
options.AllowStatusCode404Response = true;
options.ExceptionHandler = httpContext =>
{
httpContext.Response.StatusCode = StatusCodes.Status404NotFound;
return Task.CompletedTask;
};
});
})
.Configure(app =>
{
app.UseExceptionHandler();
app.Map("/throw", (innerAppBuilder) =>
{
innerAppBuilder.Run(httpContext =>
{
throw new InvalidOperationException("Something bad happened.");
});
});
});
}).Build();
await host.StartAsync();
using (var server = host.GetTestServer())
{
var client = server.CreateClient();
var response = await client.GetAsync("throw");
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
Assert.Equal(string.Empty, await response.Content.ReadAsStringAsync());
}
Assert.DoesNotContain(sink.Writes, w =>
w.LogLevel == LogLevel.Warning
&& w.EventId == 4
&& w.Message == "No exception handler was found, rethrowing original exception.");
}
}
}