Skip to content

[release/6.0] Throw for bad requests intended for minimal route handlers in development #36072

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Sep 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1291,6 +1291,53 @@ public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
}
}

[Fact]
public async Task DeveloperExceptionPageWritesBadRequestDetailsToResponseByDefaltInDevelopment()
{
var builder = WebApplication.CreateBuilder(new WebApplicationOptions() { EnvironmentName = Environments.Development });
builder.WebHost.UseTestServer();
await using var app = builder.Build();

app.MapGet("/{parameterName}", (int parameterName) => { });

await app.StartAsync();

var client = app.GetTestClient();

var response = await client.GetAsync("/notAnInt");

Assert.False(response.IsSuccessStatusCode);
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
Assert.Contains("text/plain", response.Content.Headers.ContentType.MediaType);

var responseBody = await response.Content.ReadAsStringAsync();
Assert.Contains("parameterName", responseBody);
Assert.Contains("notAnInt", responseBody);
}

[Fact]
public async Task NoExceptionAreThrownForBadRequestsInProduction()
{
var builder = WebApplication.CreateBuilder(new WebApplicationOptions() { EnvironmentName = Environments.Production });
builder.WebHost.UseTestServer();
await using var app = builder.Build();

app.MapGet("/{parameterName}", (int parameterName) => { });

await app.StartAsync();

var client = app.GetTestClient();

var response = await client.GetAsync("/notAnInt");

Assert.False(response.IsSuccessStatusCode);
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
Assert.Null(response.Content.Headers.ContentType);

var responseBody = await response.Content.ReadAsStringAsync();
Assert.Equal(string.Empty, responseBody);
}

class PropertyFilter : IStartupFilter
{
public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
<Compile Include="$(SharedSourceRoot)ProblemDetailsJsonConverter.cs" LinkBase="Shared"/>
<Compile Include="$(SharedSourceRoot)HttpValidationProblemDetailsJsonConverter.cs" LinkBase="Shared" />
<Compile Include="$(SharedSourceRoot)RoutingMetadata\AcceptsMetadata.cs" LinkBase="Shared" />
<Compile Include="$(SharedSourceRoot)TypeNameHelper/TypeNameHelper.cs" LinkBase="Shared"/>
</ItemGroup>

<ItemGroup>
Expand Down
2 changes: 2 additions & 0 deletions src/Http/Http.Extensions/src/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ Microsoft.AspNetCore.Http.RequestDelegateFactoryOptions.RouteParameterNames.get
Microsoft.AspNetCore.Http.RequestDelegateFactoryOptions.RouteParameterNames.init -> void
Microsoft.AspNetCore.Http.RequestDelegateFactoryOptions.ServiceProvider.get -> System.IServiceProvider?
Microsoft.AspNetCore.Http.RequestDelegateFactoryOptions.ServiceProvider.init -> void
Microsoft.AspNetCore.Http.RequestDelegateFactoryOptions.ThrowOnBadRequest.get -> bool
Microsoft.AspNetCore.Http.RequestDelegateFactoryOptions.ThrowOnBadRequest.init -> void
Microsoft.AspNetCore.Mvc.ProblemDetails
Microsoft.AspNetCore.Mvc.ProblemDetails.Detail.get -> string?
Microsoft.AspNetCore.Mvc.ProblemDetails.Detail.set -> void
Expand Down
168 changes: 101 additions & 67 deletions src/Http/Http.Extensions/src/RequestDelegateFactory.cs

Large diffs are not rendered by default.

10 changes: 9 additions & 1 deletion src/Http/Http.Extensions/src/RequestDelegateFactoryOptions.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.Extensions.Logging;

namespace Microsoft.AspNetCore.Http
{
/// <summary>
/// Options for controlling the behavior of <see cref="RequestDelegate" /> when created using <see cref="RequestDelegateFactory" />.
/// Options for controlling the behavior of the <see cref="RequestDelegate" /> when created using <see cref="RequestDelegateFactory" />.
/// </summary>
public sealed class RequestDelegateFactoryOptions
{
Expand All @@ -17,5 +19,11 @@ public sealed class RequestDelegateFactoryOptions
/// The list of route parameter names that are specified for this handler.
/// </summary>
public IEnumerable<string>? RouteParameterNames { get; init; }

/// <summary>
/// Controls whether the <see cref="RequestDelegate"/> should throw a <see cref="BadHttpRequestException"/> in addition to
/// writing a <see cref="LogLevel.Debug"/> log when handling invalid requests.
/// </summary>
public bool ThrowOnBadRequest { get; init; }
}
}
Loading