简体   繁体   中英

Angular 8 post formData to ASP.NET Core API cannot bind IEnumerable/List

As title says

TypeScript model

export interface RigheOrdiniBuoniSpesaData {
  id: number;
  id_ordine: number;
  id_taglio_buono_spesa: number;
  quantita: number;
}

which is part of another bigger object:

export class OrdiniBuoniSpesaData {
  id: number;
  // OTHER FIELD
  // OTHER FIELD
  // OTHER FIELD
  righe_ordine: RigheOrdiniBuoniSpesaTableData;
}

Save method

saveOrder(model: OrdiniBuoniSpesaData) {
    const headerPost: HttpHeaders = new HttpHeaders();
    headerPost.set('Content-type', 'application/x-www-form-urlencoded');
    const formData: FormData = new FormData();
    formData.append('id_cliente', model.id_cliente.toString());
    // VARIOUS FORM FIELDS
    //THIS IS ARRAY DATA
    formData.append('righe_ordine', JSON.stringify(model.righe_ordine));
    return this.http
        .post<boolean>(
          requestURL,
          formData,
          { headers: headerPost }
        )
        .pipe(
          catchError(this.handleError)
        );
}

Order json (valid Json) is visible in Chrome request capture clearly along with all data:

[{"id":0,"id_ordine":0,"id_taglio_buono_spesa":1,"quantita":1},{"id":0,"id_ordine":0,"id_taglio_buono_spesa":1,"quantita":1},{"id":0,"id_ordine":0,"id_taglio_buono_spesa":1,"quantita":1},{"id":0,"id_ordine":0,"id_taglio_buono_spesa":3,"quantita":14}]

On API Side

Receiving model for JSON

public class RigheOrdiniBuoniSpesaViewModel
{
    public long id { get; set; }
    public long id_ordine { get; set; }
    public long id_taglio_buono_spesa { get; set; }
    public int quantita { get; set; }
}

Which is in

public class OrdiniBuoniSpesaViewModel 
    {
        public long id { get; set; }
        //OTHER VARIOUS FIELDS
        //I TRIED ALSO WITH LIST INSTEAD OF IENUMERABLE
        public IEnumerable<RigheOrdiniBuoniSpesaViewModel> righe_ordine {get;set;}
    }

(I TRIED ALSO WITH LIST INSTEAD OF IENUMERABLE, STILL NO LUCK!)

Api controller signature:

[HttpPost]
public async Task<IActionResult> PostSaveOrder([FromForm] OrdiniBuoniSpesaViewModel model) 
{.....code}

All the fields are binded correctly except for the righe_ordine array! I can see every field correctly but the array has count = 0.

Strangely enough, if I examine the asp net request object (this.Request.Form) in the QuickWatch debug in visual studio:

this.Request.Form["righe_ordine"]
{[{"id":0,"id_ordine":0,"id_taglio_buono_spesa":1,"quantita":1},
{"id":0,"id_ordine":0,"id_taglio_buono_spesa":1,"quantita":1},
{"id":0,"id_ordine":0,"id_taglio_buono_spesa":1,"quantita":1},
{"id":0,"id_ordine":0,"id_taglio_buono_spesa":3,"quantita":14}]}    

Microsoft.Extensions.Primitives.StringValues

is present and correctly populated..... but for some reason binding it to the OrdiniBuoniSpesaViewModel fails....

What am I doing wrong? Any idea?

EDIT:

For the moment the only solution I found is to directly catch the value just after entering the controller:

string righeJson = this.Request.Form["righe_ordine"].ToString();
if(!string.IsNullOrEmpty(righeJson))
      model.righe_ordine = JsonConvert.DeserializeObject<IEnumerable<RigheOrdiniBuoniSpesaViewModel>>(righeJson);

I think you need to change your model name like this

In your js code

formData.append('righeOrdine', JSON.stringify(model.righe_ordine));

and c#

public class OrdiniBuoniSpesaViewModel 
    {
        public long id { get; set; }
        //OTHER VARIOUS FIELDS
        //I TRIED ALSO WITH LIST INSTEAD OF IENUMERABLE
        public IEnumerable<RigheOrdiniBuoniSpesaViewModel> RigheOrdine {get;set;}
    }

Update: Just for enhancement

Maybe you need to parse it before using it in your controller

You can read my full code here

We will need to create interface and class to implement it.

public interface IJsonParseService<T> where T : class
{
     T ToObject(string json);
}

public class JsonParseService<T> : IJsonParseService<T> where T : class
{
    public T ToObject(string json)
    {
      return JObject.Parse(json).Root.ToObject<T>();
    }
}

Then register it

services.AddScoped(typeof(IJsonParseService<>), typeof(JsonParseService<>));

So your code should be something like this

private readonly IJsonParseService<RigheOrdiniBuoniSpesaViewModel> _jsonParsePostOptionDefaultVm;

jsonParsePostOptionDefaultVm.ToObject(viewModel.RigheOrdiniBuoniSpesaViewModel); 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM