Home > Software engineering >  Complex binding for list not working .net 6 in [FromForm]
Complex binding for list not working .net 6 in [FromForm]

Time:10-20

I am trying to pass complex list of data to .net core web api controller but values are not binding, below is the code that I am using.

public IActionResult Add([FromForm]List<SponsorViewModel> sponsorDetailsList,
                                                          IFormFile profilePic)

Can anyone please help? I already checked other stack overflow questions but it is not solving the issue.

CodePudding user response:

I found that sending multiple complex objects with files are not properly supported and you need to process both differently in .NetCore 6.

How are you sending data from client side ?

If using AJAX, you need to send a FormData and disable processing data and its content type.

let myObject = {...}; // your object
let array_of_files = [...]; // your files as an array

let formData = new FormData();

// set the object as the first element to be sent
formData.append("sponsorDetailsList", JSON.stringify(myObject));

// set the files as to send them after the object
$.each(array_of_files , function(i, file) {
    formData.append("profilePic", file);
});

$.ajax({
    type: "post",
    url: "?handler=Add",
    dataType: "json",
    data: formData,
    processData: false,
    contentType: false,
    headers: { "RequestVerificationToken": $("input[name=\"__RequestVerificationToken\"]").val() },
    success: function(response) {
    },
    error: function(xhr, ajaxOptions, thrownError) {
    }
});

And in your controller (assuming you are using Razor pages, adapt it if not)

public IActionResult OnPostAdd([FromForm] List<IFormFile> profilePic) {
    // need to deserialize sponsorDetailsList separately
    try {
        List<SponsorViewModel> sponsorDetailsList = Enumerable.Empty<SponsorViewModel>().ToList();

        foreach (var data in HttpContext.Request.Form.Keys.Select((val, i) => new { key = val, intIndex = i })) {
            if (data.intIndex == 0) // first element sent is the object
                sponsorDetailsList = JsonConvert.DeserializeObject<IEnumerable<SponsorViewModel>>(!string.IsNullOrWhiteSpace(HttpContext.Request.Form[data.key]) ? HttpContext.Request.Form[data.key] : new Microsoft.Extensions.Primitives.StringValues());
        }
    }
    catch (Exception ex) {
        // error occured while deserializing
    }
}

CodePudding user response:

I assume that Since files are attached in the body, during form submit is in multipart form data. So try using [FromBody] instead of [FromForm]

CodePudding user response:

The form key/value pair looks like this

Key: sponsorDetailsList[0][Id]
Value: 1

Key: sponsorDetailsList[0][Name]
Value: John

cURL format for example

curl --location --request POST 'https://localhost:7149/api' \
--form 'sponsorDetailsList[0][Id]="1"' \
--form 'sponsorDetailsList[0][Name]="John"'

Tested in Postman. Works well with both List and File together.

Update

This is a bare minimum of working code

form

<form action="/api" method="post" enctype="multipart/form-data">
    <input type="number" name="sponsorDetailsList[0][Id]" />
    <input type="text" name="sponsorDetailsList[0][Name]" />
    <input type="file" name="profilePic" />
    <input type="submit" value="Submit">
</form>

controller method

[HttpPost]
public IActionResult Add([FromForm] List<SponsorViewModel> sponsorDetailsList, IFormFile profilePic)
{
    return Ok();
}

I think you can imagine a more complex scenario, even with JS and so on.

CodePudding user response:

What it is a POST request, Data will come in the request body. try [FromBody]

[HttpPost]
public IActionResult Add([FromBody]List<SponsorViewModel> sponsorDetailsList,                                                          IFormFile profilePic)
  • Related