Description
When using the new "Map*" methods to build minimal APIs via the RouteDelegateFactory
, it can be difficult to diagnose the cause of 400 and 415 responses that are implicitly returned when the mapped route handler's parameters cannot be satisfied from the request, either via the implicit parameter binding behavior or TryParse' and 'BindAsync
methods on the parameter target types.
It would be helpful if when in development (i.e. Environment.IsDevelopment() == true
) instead of implicitly returning the response with a 4xx status code, a BadHttpRequestException
was thrown instead, with the relevant status code set and an appropriate exception message added, making it clear why the exception/status code is being throw/set. With the DeveloperExceptionPageMiddleware
on (which it is by default in development in .NET 6 when using WebApplication
) the exception message and stack trace will be returned in the response body, making it much clearer why the invocation of the route handler failed.
This behavior should be controllable via a new options type RouteHandlerOptions
with boolean property ThrowOnBadRequest
that is configured by default to be true
when Environment.IsDevelopmet()
is true. The default configuration would be achieved via an internal type implementing IConfigureOptions<RouteHandlerOptions>
that is registered in DI when IServiceCollection.AddRouting()
is called.
Related:
- RequestDelegateFactory should return "415 Unsupported Media Type" response when parameter binding and the request isn't JSON #35856
- DeveloperExceptionPageMiddleware should set response status code from BadHttpRequestException #35857
Proposed APIs
namespace Microsoft.AspNetCore.Routing
{
+ public class RouteHandlerOptions
+ {
+ public bool ThrowOnBadRequest { get; set; }
+ }
}
namespace Microsoft.AspNetCore.Http
{
public class RequestDelegateFactoryOptions
{
+ public bool ThrowOnBadRequest { get; init; }
}
}
Example usage
var builder = WebApplication.CreateBuilder(args);
// Enable exceptions for implicit 4xx responses in custom "LocalDev" environment
var isDev = app.Environment.IsDevelopment() || app.Environment.IsEnvironemnt("LocalDev");
builder.Services.Configure<RouteHandlerOptions>(options => options.ThrowOnBadRequest = isDev);
var app = builder.Build();