Skip to content

Inferring FromBody.AllowEmptyBehavior = Allow based nullability information #39754

@brunolins16

Description

@brunolins16

Current design

Today, MVC infer optionality for parameters/properties based on nullability or if they have default value for all Binding Sources, eg.:

#nullable enable
    public IActionResult Post([FromBody] string? name);
    public IActionResult Get([FromQuery] string? name);
    public IActionResult Post([FromForm] string? name);
#nullable restore

Or

#nullable disable
    public IActionResult Post([FromBody] string name = null) ;
    public IActionResult Get([FromQuery] string name = null);
    public IActionResult Post([FromForm] string name = null);
#nullable restore

All examples above will allow the null value for the parameter name, however, when the binding From Body (inferred or not) the current default behavior is fail when the Content-Length == 0.

{
    "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
    "title": "One or more validation errors occurred.",
    "status": 400,
    "traceId": "00-1a27854a7f1211e53fbc64e054801c11-a79404ee342e26ff-00",
    "errors": {
        "": [
            "A non-empty request body is required."
        ]
    }
}

Currently, are available 2 options to override this behavior and any of those available options are based on the Nullability information and need to be explicitly specified by the user.

Globally:

builder.Services.Configure<MvcOptions>(options =>
{
    options.AllowEmptyInputInBodyModelBinding = true;
});

Scoped:

public IActionResult Post([FromBody(EmptyBodyBehavior = EmptyBodyBehavior.Allow)] string? name);

Proposed Change

As part of the idea to bring Minimal APIs enhancements to MVC the proposal is applying the same default behavior and allow empty input body (Content-Length = 0) when the parameter/property is nullable or has the default value.

The suggestion is to always allow empty input (Content-Length = 0) when a [FromBody] parameter/property sets a default value or is nullable without allowing or requiring configuration.

After this change the following scenarios will allow an empty input:

#nullable disable
    public IActionResult Action([FromBody] string value);
    public IActionResult Action([FromBody] string value = null);
#nullable restore
#nullable enable
    public IActionResult Action([FromBody] string? value);
    public IActionResult Action([FromBody] string? value = null);
#nullable restore

Usage Examples

If the users are affected by this change and they would like a different behavior, the simplest way to avoid it is to define the action parameter/property correctly based on the optionality, as the examples listed below.

Required parameter in a disabled nullable context

Before

#nullable disable
    public IActionResult Action([FromBody] string value);
    public IActionResult Action([FromBody] string value = null);
#nullable restore

After

#nullable disable
    public IActionResult Action([FromBody][Required] string value);
#nullable restore

Required parameter in an enabled nullable context

Before

#nullable enable
    public IActionResult Action([FromBody] string? value);
    public IActionResult Action([FromBody] string? value = null);
#nullable restore

After

#nullable enable
    public IActionResult Action([FromBody] string value);
#nullable restore

Metadata

Metadata

Assignees

Labels

breaking-changeThis issue / pr will introduce a breaking change, when resolved / merged.feature-model-bindingold-area-web-frameworks-do-not-use*DEPRECATED* This label is deprecated in favor of the area-mvc and area-minimal labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions