Home > Software design >  Pass FormData Item array of object angular
Pass FormData Item array of object angular

Time:12-06

How can I pass FormData to api with array of obejcts inside?

i am trying like this

enter image description here

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 be POST-submitted as either application/x-www-form-urlencoded or as multipart/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 or XMLHttpRequest) it is commonplace to POST data as JSON (application/json) instead of either of the 2 <form> encodings.
        • Angular's HttpClient uses fetch internally.
        • It would be nice if <form> could be used to submit JSON too, without any scripting; it doesn't, oh well.
  • In your case specifically, your Items is a List<...> 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 be null or empty and there won't be any warnings or errors (which is annoying).

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 );
    }
}
  • Related