-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Allow IFormFile parameters annotated with [FromForm] to be correctly … #8452
Conversation
…bound in ApiControllers Fixes #8311
@@ -166,5 +170,12 @@ private bool IsComplexTypeParameter(ParameterModel parameter) | |||
.GetMetadataForType(parameter.ParameterInfo.ParameterType); | |||
return metadata.IsComplexType && !metadata.IsCollectionType; | |||
} | |||
|
|||
private static bool IsFormFile(Type parameterType) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BindingSource.Form
is non-greedy, while BindingSource.FormFile
that's inferred from model metadata is greedy. The difference causes the parameter name to be reset by ApiController
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The above code is intended to reset the name iff the binding source is non-greedy.
@@ -112,7 +114,8 @@ internal void InferBoundPropertyModelPrefixes(ControllerModel controllerModel) | |||
if (property.BindingInfo != null && | |||
property.BindingInfo.BinderModelName == null && | |||
property.BindingInfo.BindingSource != null && | |||
!property.BindingInfo.BindingSource.IsGreedy) | |||
!property.BindingInfo.BindingSource.IsGreedy && | |||
!IsFormFile(property.ParameterType)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Something else is going on here because this line should be redundant. IFormFile
and IEnumerable<IFormFile>
parameters should be inferred to have BindingSource.FromFile
. IsGreedy
is true
for that binding source. This line and line 139 should not be reachable for the parameters affected by #8311. (Modulo the #7770 fix for parameters that aren't exactly IFormFile
or IFormFileCollection
.)
@pranavkm did you debug the scenario and confirm these BinderModelName
settings are the issue? If yes, why were property.BindingInfo.BindingSource.IsGreedy
or parameter.BindingInfo.BindingSource.IsGreedy
(below) false
for an IFormFile
property or parameter?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The issue specifically manifests in this scenario: Post([FromForm] IFormFile formFile)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it now. Thanks for the offline conversation @pranavkm
private static bool IsFormFile(Type parameterType) | ||
{ | ||
return typeof(IFormFile).IsAssignableFrom(parameterType) || | ||
typeof(IFormFileCollection).IsAssignableFrom(parameterType) || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't need to check for IFormFileCollection
because that implements IEnumerable<IFormFile>
.
@@ -166,5 +170,12 @@ private bool IsComplexTypeParameter(ParameterModel parameter) | |||
.GetMetadataForType(parameter.ParameterInfo.ParameterType); | |||
return metadata.IsComplexType && !metadata.IsCollectionType; | |||
} | |||
|
|||
private static bool IsFormFile(Type parameterType) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The above code is intended to reset the name iff the binding source is non-greedy.
@@ -720,6 +720,87 @@ public void InferParameterModelPrefixes_SetsModelPrefix_ForComplexTypeFromValueP | |||
Assert.Equal(string.Empty, parameter.BindingInfo.BinderModelName); | |||
} | |||
|
|||
[Fact] | |||
public void InferParameterModelPrefixes_DoesNotSetModelPrefix_ForFormFileParametersAnnotatedWithFromForm() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These new tests aren't really regression tests for #8311. Need integration or functional tests that include the default BindingSourceMetadataProvider
s. See
modelMetadataDetailsProviders.Add(new BindingSourceMetadataProvider(typeof(IFormFile), BindingSource.FormFile)); | |
modelMetadataDetailsProviders.Add(new BindingSourceMetadataProvider(typeof(IFormCollection), BindingSource.FormFile)); | |
modelMetadataDetailsProviders.Add(new BindingSourceMetadataProvider(typeof(IFormFileCollection), BindingSource.FormFile)); | |
modelMetadataDetailsProviders.Add(new BindingSourceMetadataProvider(typeof(IEnumerable<IFormFile>), BindingSource.FormFile)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We use TestModelMetadataProvider
that's set up with these detail providers in these tests
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🆗
} | ||
|
||
[Fact] | ||
public void InferParameterModelPrefixes_DoesNotSetModelPrefix_ForFormFileCollectionParametersAnnotatedWithFromForm() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rename. This test covers properties, not parameters.
🆙 📅 |
29b6b99
to
43f5dd6
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. The main question I have is whether we should similarly special-case CancellationToken
, IFormCollection
, and anything with a specified BindingInfo.BinderType
to ignore BindingSource
(as the binder providers do). Thoughts?
After another offline conversation, @pranavkm has agreed to file a couple of bugs to track separately. In addition, neither of us believe |
@dougbu would you mind filing the issue with the |
@pranavkm after experimenting a bit, I don't think It's possible to subclass either attribute or implement |
…bound in ApiControllers
Fixes #8311