-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Add support for optional FromBody parameters #22634
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
Conversation
7c8d4ea to
d57ed85
Compare
|
I'll fix the source build. Just wanted to vet the design. |
javiercn
left a comment
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.
Changes look solid, I would need to look a bit more in depth to see if we are missing something since I'm not an expert in this area.
dougbu
left a comment
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.
Please change the IAllowEmptyInputInBodyModelBinding definition.
More generally, I'm unsure whether this approach is better or worse than a new MvcOption.AllowEmptyInputInBodyModelBindingIfSet option. We could implement that using ApiParameterDescription.DefaultValue.
| /// <remarks> | ||
| /// When configured, takes precedence over <see cref="MvcOptions.AllowEmptyInputInBodyModelBinding"/>. | ||
| /// </remarks> | ||
| public bool AllowEmptyInputInBodyModelBinding |
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.
Suggest the property in IAllowEmptyInputInBodyModelBinding should be non-nullable too. I don't see a use case for a tri-state property here.
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.
I was looking at being able to distinguish these two scenario:
.AddControllers(options => options.AllowEmptyInputInBodyModelBinding = true);
...
public IActionResult Post([FromBody(AllowEmptyInputInBodyModelBinding = false)] /* this API always require a body */ LoginModel model)
public IActionResult Post([FromBody] /* I'm ok with whatever was configured in MvcOptions */ CommentModel model)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.
Then this property should be of type bool?
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.
Unfortunately attributes cannot have nullable properties that can be assigned to: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/attributes#attribute-parameter-types. We could create an enum type to represent it. While it might be more correct to have an explicit distinction between fallback to 'system default' vs 'explicitly false', users don't really query the attribute so it seems like overkill.
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.
Perhaps overkill but the tri-state approach you want won't work as long as the only IAllowEmptyInputInBodyModelBinding implementation has a non-nullable bool.
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 interface IAllowEmptyInputInBodyModelBinding is non-public. It's largely a result of weird layering - BindingInfo is in Abstractions, FromBody is in Mvc.Core. We're free to assign it the shape we think works best.
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.
[FromBody(AllowEmpty = AllowEmptyBodyBehavior.Default)]
[FromBody(AllowEmpty = AllowEmptyBodyBehavior.Reject)]
[FromBody(AllowEmpty = AllowEmptyBodyBehavior.Allow)]
enum AllowEmptyBodyBehavior
{
Default,
Reject,
Allow
}
|
|
||
| _options = options; | ||
| _formatters = formatters; | ||
| _readerFactory = readerFactory.CreateReader; |
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.
Why the reordering?
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.
Messed up. Will undo
|
Thanks both of you for the quick review. As @dougbu, relying on the default value of the parameters would have been super nice and most intuitive. I had hoped that's what we could do but there are a few issues with it that made me use this approach: a) We don't currently have access to parameter values in the binder \ binder factory. The best way I could think of resolving this is by adding b) Relying on default parameter values alone doesn't help solve it for properties. It would be nice to solve the problem for both kinds of bound types - parameters and properties. Using a property was something a user suggested - aspnet/Mvc#6920 (comment) and it has a fair number of upvotes so it doesn't seem entirely unappealing. |
|
@pranavkm got it, thanks for the explanation. That just leaves the |
|
Thank you for submitting this for API review. This will be reviewed by @dotnet/aspnet-api-review at the next meeting of the ASP.NET Core API Review group. Please ensure you take a look at the API review process documentation and ensure that:
|
src/Mvc/Mvc.Abstractions/ref/Microsoft.AspNetCore.Mvc.Abstractions.netcoreapp.cs
Outdated
Show resolved
Hide resolved
|
Hello @pranavkm! Because this pull request has the p.s. you can customize the way I help with merging this pull request, such as holding this pull request until a specific person approves. Simply @mention me (
|
dougbu
left a comment
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.
One teensy fixup…
| { | ||
| /// <summary> | ||
| /// Uses the framework default behavior for processing empty bodies. | ||
| /// This is typically configured using <c>MvcOptions.AllowEmptyInputInBodyModelBinding</c> |
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.
End comment with another period
* Add support for optional FromBody parameters Fixes #6878 * Fixup nullable * Changes per API review
Fixes #6878
public enum EmptyBodyBehavior { Default = 0, Allow = 1, Disallow = 2, } public partial class FromBodyAttribute : System.Attribute, Microsoft.AspNetCore.Mvc.ModelBinding.IBindingSourceMetadata { public FromBodyAttribute() { } + public EmptyBodyBehavior EmptyBodyBehavior { get { throw null; } set { } } } public partial class BindingInfo { public BindingInfo() { } public BindingInfo(Microsoft.AspNetCore.Mvc.ModelBinding.BindingInfo other) { } + public EmptyBodyBehavior EmptyBodyBehavior { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } } public partial class ApiParameterDescription { public ApiParameterDescription() { } + public Microsoft.AspNetCore.Mvc.ModelBinding.BindingInfo BindingInfo { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } }