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)