Request model binding with `FromQuery` properties `AsParameters` results in all properties being required.
- Dominant language
- C#
- Stars
- 38.4k
- Forks
- 10.9k
- Avg merge
- 2d 10h
- Merged PRs (30d)
- 281
Description
### Is there an existing issue for this?
- [X] I have searched the existing issues
### Describe the bug
Binding a model exclusively using `FromQuery` properties `AsParameters` results in all properties being treated as if required.
An endpoint binding a POCO model as parameters treats each and every property in the `MyReq` model as required.
```csharp
[AsParameters] MyReq request
```
Properties in the model which are not required should not be required in the search string.
The definition below illustrates the expectation, but not the current implementation, because currently each one of these properties is required, even those with default values.
```csharp
public sealed record MyReq
{
[FromQuery()]
public string Prop1{ get; init; } = "*"; // not required
[FromQuery()]
public decimal? Prop2 { get; init; } // not required
[FromQuery()]
public string? Prop3 { get; init; } // not required
[FromQuery()]
public required string Prop4 {get; init; } // required
[FromQuery(), Required]
public string Prop5 { get; init; } = ""; // required
[FromQuery()]
public int Prop6 { get; init; } // not required
[FromQuery()]
public string Prop7 { get; init; } // not required (has compiler warning)
}
```
### Expected Behavior
Given a request model, properties with default values and without the `required` modifier or annotation, must not be recognized as required parameters.
### Steps To Reproduce
Model:
```csharp
public sealed record ProfitRequest
{
[FromQuery(Name = "gem_name")]
public string GemNameWindcard { get; init; } = "*";
[FromQuery(Name = "min_sell_price_chaos")]
public decimal? MinSellPriceChaos { get; init; } = null;
[FromQuery(Name = "max_buy_price_chaos")]
public decimal? MaxBuyPriceChaos { get; init; } = null;
[FromQuery(Name = "min_experience_delta")]
public decimal? MinExperienceDelta { get; init; } = null;
}
```
Builder:
```csharp
var app = builder.Build();
app
.MapGet("gem-profit", async (
[FromServices] ProfitService profitService,
[AsParameters] ProfitRequest request,
CancellationToken cancellationToken = default
) =>
{
var data = await profitService.GetProfitAsync(request, cancellationToken).ConfigureAwait(false);
return data;
});
```
Failed request:
```http
GET http://127.0.0.1:5000/gem-profit?min_experience_delta=65000000
```
Successful request:
```http
GET http://127.0.0.1:5000/gem-profit?gem_name=*&min_sell_price_chaos=0&max_buy_price_chaos=0&min_experience_delta=65000000&items_offset=0&items_count=10
```
### Exceptions (if any)
Microsoft.AspNetCore.Http.BadHttpRequestException: Required parameter "string GemNameWindcard" was not provided from query string.
at lambda_method933(Closure, Object, HttpContext)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext)
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
### .NET Version
8.0.100
### Anything else?
.NET SDK:
Version: 8.0.100
Commit: 57efcf1350
Workload version: 8.0.100-manifests.6a1e483a
Runtime Environment:
OS Name: Windows
OS Version: 10.0.19045
OS Platform: Windows
RID: win-x64
Base Path: C:\Program Files\dotnet\sdk\8.0.100\
.NET workloads installed:
Workload version: 8.0.100-manifests.6a1e483a
There are no installed workloads to display.
Host:
Version: 8.0.0
Architecture: x64
Commit: 5535e31a71
.NET SDKs installed:
3.1.426 [C:\Program Files\dotnet\sdk]
6.0.417 [C:\Program Files\dotnet\sdk]
7.0.404 [C:\Program Files\dotnet\sdk]
8.0.100 [C:\Program Files\dotnet\sdk]
.NET runtimes installed:
Microsoft.AspNetCore.App 3.1.32 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 6.0.25 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 7.0.14 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 8.0.0 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.NETCore.App 3.1.32 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 6.0.25 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 7.0.14 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 8.0.0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.WindowsDesktop.App 3.1.32 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 6.0.25 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 7.0.14 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 8.0.0 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Contributor guide
Assessment
This issue has not been assessed yet.