'How to send object and file at the sime time from Angular to .net api?

I Try to send object and file at the same time to .net api but it dont work.

I am trying to send data with FormData on angular side but FormData does not accept objects. When I don't send it with FormData, I can't receive the Files on the .net side.

How can I send the files and the object to the .net side at the same time?

angular :

const formData = new FormData();
formData.append('type',this.form.get('type').value)
formData.append('productId',this.form.get('product').value);
formData.append('serialNo',this.form.get('serialNo').value);
formData.append('companyId',this.form.get('company').value);
formData.append('unitPrice',this.form.get('unitPrice').value.toString().replace('.',','));
formData.append('description',this.form.get('description').value);
formData.append('properties',this._helperService.mapToObj(this.properties))

const files = this.form.get('files').value as FileList;
const fileArr = Array.from(files);
if(fileArr.length > 0){
  fileArr.forEach(f => formData.append('files',f))
}

this._stockReceiptService.saveStockReceipt(formData).pipe(takeUntil(this.subject)).subscribe(resp => {
  this.success.text = "Stok girişi kaydedildi";
  this.success.fire();
  console.log("Apiden gelen => ", resp);
}, err => {
  this.error.text = "Stok girişi yapılırken hata oluştu";
  this.error.fire();
});

}

SaveStockReceipt Service:

saveStockReceipt(post: any): Observable<any>{
return this._http.post<any>(this.apiURL + '/stock/stockReceipt',post);
}

.net model

public class CreateStockVModel
{
[Required(ErrorMessage = "Type alanı zorunlu alandır.")]
public int Type { get; set; }

[Required(ErrorMessage = "ProductId alanı zorunlu alandır.")]
public int ProductId { get; set; }

[Required(ErrorMessage = "SerialNo alanı zorunlu alandır.")]
public string? SerialNo { get; set; }

[Required(ErrorMessage = "CompanyId alanı zorunlu alandır.")]
public int CompanyId { get; set; }

public decimal? UnitPrice { get; set; }
public string? Description { get; set; }
public List<IFormFile>? Files { get; set; }
public Dictionary<int,int>? Properties { get; set; }
}

controller

[HttpPost]
public async Task<IActionResult> StockReceipt([FromForm] CreateStockVModel vModel)
{
    return Ok(vModel);
}


Solution 1:[1]

Maybe you should try to convert C# model to TS interface and put it to saveStockReceipt instead of post: any

Solution 2:[2]

I will write the solution in an abstract way because it will take time. But basically, the workflow will be as follows:

Send the files as a stream with the request to the backend:

<input type="file" name="file" id="file"(change)="onFileChanged($event)" multiple />
....


export class MyComponent {
   public files: any[];
   ...
   onFileChanged(event: any) {
    this.files.push(event.target.files[0]);
  }
  upload() {
    const formData = new FormData();
    this.files.forEach(file => formData.append(this.file.name, this.file, this.file.name));
    ... Apend the rest
    this.httpClient.post(url, formData, { headers: headers }).subscribe(...);
  }
}

You need to read the files in the backend from the request:

   [HttpPost]
   public async Task<IActionResult> StockReceipt([FromForm] CreateStockVModel vModel)
   {
      var files = this.Request.Form.Files[0]; // you can iterate throw other files
      if (files.Length > 0)
      {
          var fileName = ContentDispositionHeaderValue.Parse(files.ContentDisposition).FileName.Trim('"');
          var fullPath = Path.Combine(pathToSave, fileName);
          using (var stream = new FileStream(fullPath, FileMode.Create))
          {
              // here you have the stream
          }
    }
      return Ok();
   }

For more information, see this link: https://code-maze.com/upload-files-dot-net-core-angular/

Solution 3:[3]

It's because you defined the Files as List but sending files as single file, so to correct the code replace the following:

if(fileArr.length > 0){
  fileArr.forEach(f => formData.append('files',f))
}

with:

let files = [];
if(fileArr.length > 0){
  fileArr.forEach(f => files.push(f));
  formData.append('files', files);
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 yaroslove
Solution 2 Samy Sammour
Solution 3 Elyas Esna