How can I pass FormData to api with array of obejcts inside?
i am trying like this
this is the payload of request how can i get all items with other data i .net core c# Api?
public class BackgroundCheckParam
{
public Guid EmpId { get; set; }
public List<BackgroundChecksResults> Items { get; set; }
public IFormFile ResultPdf { get; set; }
public IFormFile DisclosurePdf { get; set; }
public DateTime CompleteDate { get; set; }
}
public class BackgroundChecksResults
{
public string Type { get; set; }
public string Result { get; set; }
}
public ResponseResult AddBackgroundCheck([FromForm] BackgroundCheckParam data)
{
}
All other is fine I am receiving everything but Items. Items are always 0.
CodePudding user response:
It isn't working because you're mixing JSON and traditional
<form>
data.- Some background info:
- In "normal" HTML, without scripting or AJAX, a
<form>
can bePOST
-submitted as eitherapplication/x-www-form-urlencoded
or asmultipart/form-data
.application/x-www-form-urlencoded
is an almost-human-readable textual representation of every key value pair. e.g.key1=value1&key2=value2
.multipart/form-data
is a binary encoding. You need to use this option when posting files from an<input type="file">
.
- With JavaScript-initiated HTTP requests (using
fetch
orXMLHttpRequest
) it is commonplace to POST data as JSON (application/json
) instead of either of the 2<form>
encodings.- Angular's
HttpClient
usesfetch
internally. - It would be nice if
<form>
could be used to submit JSON too, without any scripting; it doesn't, oh well.
- Angular's
- In "normal" HTML, without scripting or AJAX, a
- Some background info:
In your case specifically, your
Items
is aList<...>
being represented as a JSON array in a single form item when it should be sent as multiple form items, one for each value.The solution is to represent
Items
in a way compatible with ASP.NET's form model-binding syntax.- Specifically, each discrete value has its own form name, and each list element is referenced by a 0-based incremental index.
In your case, the keys/names for
Items
will be like:Items[0].Type = "Background" Items[0].Result = "Pass" Items[1].Type = "Foreground" Items[1].Result = "Fail" Items[2].Type = "Middleground" Items[2].Result = "Compromise"
- Note that ASP.NET (all versions) always require collection indexers to be 0-based and have no gaps between indexes, otherwise the
List<>
property will benull
or empty and there won't be any warnings or errors (which is annoying).
- Note that ASP.NET (all versions) always require collection indexers to be 0-based and have no gaps between indexes, otherwise the
So you should have something like this:
// * Use `URLSearchParams` for `application/x-www-form-urlencoded`.
// * Use `FormData` for `multipart/form-data`.
const resultPdfFile = inputElement1.files[0];
const disclosurePdf = inputElement2.files[0];
const formValues = new FormData();
formValues.append( "EmpId" , "fckgw-rhqq2-yxrkt-8tg6w-2b7q8" );
formValues.append( "ResultPdf" , resultPdfFile );
formValues.append( "DisclosurePdf", disclosurePdf );
formValues.append( "CompleteDate" , "2021-12-01" );
for( let i = 0; i < items.length; i ) {
const keyPrefix = "Items[" i.toString() "].";
formValues.append( keyPrefix "Type" , items[i].type ); // e.g. "Items[0].Type"
formValues.append( keyPrefix "Result", items[i].result );
}
await postRequest( formValues );
Alternative quick-fix workaround "solution"
In your ASP.NET code, ignore the Items
member of your BackgroundCheckParam data
action parameter and JSON-decode Items
from Request.Form
:
public ResponseResult AddBackgroundCheck([FromForm] BackgroundCheckParam data)
{
IReadOnlyList<BackgroundChecksResults> items;
{
String formList = this.Request.Form["Items"];
items = JsonConvert.DeserializeObject< List<BackgroundChecksResults> >( formList );
}
}