ApiExplorer handles [FromHeader] binding (on complex type) differently to [FromQuery] binding
See original GitHub issueDescribe the bug
Given the following two actions that bind query/header params to a complex type:
public IActionResult Get1([FromQuery]CustomParams queryParams)
public IActionResult Get2([FromHeader]CustomParams headerParams)
public class CustomParams
{
public string Foo { get; set; }
public string Bar { get; set; }
}
For the first action, ApiExplorer
surfaces multiple query parameters, one for each property in the complex type. This makes sense because that’s exactly how the model binder behaves - i.e. it will look for individual query parameters and assign them to corresponding properties. However, for the second action, ApiExplorer
only surfaces a single parameter corresponding to the custom type itself. It’s my understanding that the model binder behaves the same way in both cases, and so I would expect ApiExplorer
to follow suit. Here’s an example of the relevant ApiExplorer
data (serialized as JSON):
[
{
"relativePath": "Test/Get1",
"httpMethod": "GET",
"parameters": [
{
"name": "Foo",
"source": {
"displayName": "Query",
"id": "Query",
"isGreedy": false,
"isFromRequest": true
},
"modelType": "System.String"
},
{
"name": "Bar",
"source": {
"displayName": "Query",
"id": "Query",
"isGreedy": false,
"isFromRequest": true
},
"modelType": "System.String"
}
]
},
{
"relativePath": "Test/Get2",
"httpMethod": "GET",
"parameters": [
{
"name": "headerParams",
"source": {
"displayName": "Header",
"id": "Header",
"isGreedy": true,
"isFromRequest": true
},
"modelType": "ApiExplorerIssue.Controllers.CustomParams"
}
]
}
]
To Reproduce
> git clone git@github.com:domaindrivendev/ApiExplorerIssue.git
> cd ApiExplorerIssue
> git checkout from-header-property-bindings
> dotnet run
Then navigate to "http://localhost:5000/apidescriptions" to see the ApiExplorer data
Further technical details
- ASP.NET Core version: 5.0
Issue Analytics
- State:
- Created 3 years ago
- Reactions:3
- Comments:11 (6 by maintainers)
Top Results From Across the Web
c# - How to use [FromHeader] attribute with custom model ...
Was able to make it work by using [FromHeader] attribute on model properties and [FromQuery] attribute on model itself to fool model binding...
Read more >Model Binding in ASP.NET Core
[FromQuery] - Gets values from the query string. ... Special data types. There are some special data types that model binding can handle....
Read more >Exploring the model-binding logic of minimal APIs
In this post we explore the code in CreateArgument() , and see how it fundamentally defines the model-binding behaviour of minimal APIs.
Read more >Improvements to Model Binding in ASP.NET Core
The native model-binding layer kicks in and finds any value available around the HTTP request that can be mapped to the name of...
Read more >Swashbuckle.AspNetCore
FormFile and if you apply the attribute it will be set to BindingSource.Form instead, which screws up ApiExplorer , the metadata component that...
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Thanks for contacting us. We’re moving this issue to the
Next sprint planning
milestone for future evaluation / consideration. We will evaluate the request when we are planning the work for the next milestone. To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.This becomes a whole other beast when working with Commands (CQRS) and utilizing ‘.AddEndpointFilter’ for the command, since the headers are never picked up if using a complex type:
This will cause the validation to happen before entering the endpoint, thereby causing us never to be able to validate the header.
A workaround for this is to accept the ‘headerKey’ and ‘bodyKey’ as separate parameters, map them to the command, and then validate them. But this seems like something that is not intentional.