aspnetcore icon indicating copy to clipboard operation
aspnetcore copied to clipboard

ASP.NET core inconsistent model binding from form-data and json when trying to bind to an IEnumerable<T>

Open ripebananas opened this issue 1 year ago • 0 comments

Is there an existing issue for this?

  • [X] I have searched the existing issues

Describe the bug

Model binding from form-data seems to work differently than model binding from json.

Expected Behavior

No response

Steps To Reproduce

Create a simple Web API with controllers. Also have Nullable enabled in the csproj. Create the following controller and model:

[ApiController]
[Route("[controller]")]
public class ApiController : ControllerBase
{
    [HttpPost("[action]")]
    public IActionResult PostFormData([FromForm] PostRequest request) =>
        Ok(string.Join(",", request.Values ?? ["<none>"]));

    [HttpPost("[action]")]
    public IActionResult PostJson(PostRequest request) =>
        Ok(string.Join(",", request.Values ?? ["<none>"]));
}

public record PostRequest
{
    public IEnumerable<string> Values { get; set; } = [];
}

Note that the Values property has a default value in the PostRequest record.

When calling the PostJson method on the controller, the model is bound as expected (screenshot from Postman): image

When calling the PostFormData method, though, the application returns an error: image

The error is:

{
    "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
    "title": "One or more validation errors occurred.",
    "status": 400,
    "errors": {},
    "traceId": "00-3ea96923dfbfea72ba0c067b226b3985-0d099b1cc0b1cb3d-00"
}

I might be missing something, but there seems to be other strange behavior on the PostFormData method, i.e. when the model is bound from form-data:

  • Removing the default value of [] (i.e. leaving it null), will not raise an error and the model property is bound as expected.
  • When the default value is a collection with number of elements that is equal or greater than the elements passed in the form-data (e.g. default value of ["x", "x", "x"]), then an error is not raised but the bound collection retains the default value (["x", "x", "x"]) and not the one passed in the form-data.
  • Changing the Values property type to one of string[], List<string>, ICollection<string> seems to prevent the app from raising the error.

Exceptions (if any)

No response

.NET Version

8.0.200

Anything else?

No response

ripebananas avatar Mar 13 '24 08:03 ripebananas