Skip to content

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

Merged
3 commits merged into from
Jun 22, 2020
Merged

Add support for optional FromBody parameters #22634

3 commits merged into from
Jun 22, 2020

Conversation

pranavkm
Copy link
Contributor

@pranavkm pranavkm commented Jun 6, 2020

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 { } }

@ghost ghost added the area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates label Jun 6, 2020
@pranavkm pranavkm force-pushed the prkrishn/6878 branch 5 times, most recently from 7c8d4ea to d57ed85 Compare June 7, 2020 01:11
@pranavkm pranavkm marked this pull request as ready for review June 8, 2020 17:49
@pranavkm
Copy link
Contributor Author

pranavkm commented Jun 8, 2020

I'll fix the source build. Just wanted to vet the design.

@pranavkm pranavkm added the api-suggestion Early API idea and discussion, it is NOT ready for implementation label Jun 8, 2020
Copy link
Member

@javiercn javiercn left a 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.

Copy link
Contributor

@dougbu dougbu left a 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
Copy link
Contributor

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.

Copy link
Contributor Author

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)

Copy link
Contributor

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?

Copy link
Contributor Author

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.

Copy link
Contributor

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.

Copy link
Contributor Author

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.

Copy link
Contributor Author

@pranavkm pranavkm Jun 15, 2020

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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the reordering?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Messed up. Will undo

@pranavkm
Copy link
Contributor Author

pranavkm commented Jun 8, 2020

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 bool HasDefaultValue \ object? DefaultValue to ModelMetadata. We could infer it when constructing metadata for parameters. Unfortunately, this leaves us with:

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.

@dougbu
Copy link
Contributor

dougbu commented Jun 9, 2020

@pranavkm got it, thanks for the explanation. That just leaves the IAllowEmptyInputInBodyModelBinding inconsistency from my PoV.

@pranavkm pranavkm added api-ready-for-review API is ready for formal API review - https://github.com/dotnet/apireviews and removed api-suggestion Early API idea and discussion, it is NOT ready for implementation labels Jun 10, 2020
@ghost
Copy link

ghost commented Jun 10, 2020

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:

  • The PR contains changes to the reference-assembly that describe the API change. Or, you have included a snippet of reference-assembly-style code that illustrates the API change.
  • The PR describes the impact to users, both positive (useful new APIs) and negative (breaking changes).
  • Someone is assigned to "champion" this change in the meeting, and they understand the impact and design of the change.

@pranavkm pranavkm added api-approved API was approved in API review, it can be implemented and removed api-ready-for-review API is ready for formal API review - https://github.com/dotnet/apireviews labels Jun 22, 2020
@pranavkm pranavkm added this to the 5.0.0-preview7 milestone Jun 22, 2020
@ghost
Copy link

ghost commented Jun 22, 2020

Hello @pranavkm!

Because this pull request has the auto-merge label, I will be glad to assist with helping to merge this pull request once all check-in policies pass.

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 (@msftbot) and give me an instruction to get started! Learn more here.

Copy link
Contributor

@dougbu dougbu left a 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>
Copy link
Contributor

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

@ghost ghost merged commit f7d2fac into master Jun 22, 2020
@ghost ghost deleted the prkrishn/6878 branch June 22, 2020 19:11
pranavkm added a commit that referenced this pull request Jun 22, 2020
* Add support for optional FromBody parameters

Fixes #6878

* Fixup nullable

* Changes per API review
mkArtakMSFT pushed a commit that referenced this pull request Jun 23, 2020
* Add support for optional FromBody parameters (#22634)

* Add support for optional FromBody parameters

Fixes #6878

* Fixup nullable

* Changes per API review

* Fixup doc comment (#23229)
This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api-approved API was approved in API review, it can be implemented area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Optional [FromBody] Model Binding
4 participants