9

I am trying to send model which part is some IFormFile type propertis which represent user avatar. But unfortunely my avatar propertis is always null, i saw a lot of exampels how to send single picture element but i can find exampels how send it when it is part of model not a single element as it is done here for example

Here is my component method in which i set this props

  editUser(model: Company) {
this.errors = '';
debugger;
console.log(model);
let fi = this.fileInput.nativeElement;
if (fi.files) {
  let fileToUpload = fi.files[0];
  model.avatarImage = fileToUpload;
}
model.id = this.company.id;
this.companyService.update(model)
  .subscribe(
  result => {
    if (result) {
    }
  },
  errors => this.errors = errors);

}

Here my company model at angular2 side

export interface Company {
id: string,
advertiseTitle: string,
advertiseDescription: string,
city: string,
street: string,
categoryId: number,
price: number,
facebookPage: string,
instagramPage: string,
avatarImage: File

}

And my put methods from client side

    update(company: Company) {  
    return this.apiService.put(`${this.path}/${company.id}`, JSON.stringify(company));
}

Put method in apiService

put(path: string, body): Observable<any> {
    debugger;
    this.setBearerHeader();
    console.log('Http Post Observable: ', path, body);
    let url = `${this.baseUrl}${path}`;
    let request = new Request({
        url: url,
        headers: this.headers,
        method: RequestMethod.Put,
        body: body
    });

    return this.http.request(request)
        .catch(this.handleError)
        .map(res => res.json())
};

Firs what i was thinking can be a reason was JSON.stringify but it don't change anything it always is empty in the request enter image description here

Here is my backend put method(ASP.NET Core)

// PUT api/values/5
[HttpPut("{id}")]
public async Task<IActionResult> Put(string id, [FromBody] CompanyViewModel dto)
{
  if (!ModelState.IsValid)
  {
    return BadRequest(ModelState);
  }

  try
  {
    if (id != dto.Id)
    {
      return BadRequest();
    }

    //var entity = _mapper.Map<Company>(dto);
    //_shopDbContext.Comapnies.Update(entity);
    Company entity =  this.Get(id);
    entity.CategoryId = dto.CategoryId;
    entity.City = dto.City;
    entity.CategoryId = dto.CategoryId;
    entity.Street = dto.Street;
    entity.Price = dto.Price;
    entity.AdvertiseTitle = dto.AdvertiseTitle;
    entity.InstagramPage = dto.InstagramPage;
    entity.FacebookPage = dto.FacebookPage;
    using (var memoryStream = new MemoryStream())
    {
      await dto.AvatarImage.CopyToAsync(memoryStream);
      entity.AvatarImage = memoryStream.ToArray();
    }
    _shopDbContext.Comapnies.Update(entity);
    await _shopDbContext.SaveChangesAsync();

    return Ok(dto);
  }
  catch (Exception ex)
  {
    throw;
  }
}

And here also remove [FromBody] don't change anything in this case.

Stefan
  • 1,431
  • 2
  • 17
  • 33

2 Answers2

8

Based on this answer I manage to submit a form including an file to asp.net core Web API from Angular 5.

model on server:

[Required]
public string ExpenseType { get; set; }
[Required]
public string Activity { get; set; }
[Required]
public string Provider { get; set; }
[Required]
public decimal RequestedAmount { get; set; }
[Required]
public IFormFile InvoiceFile { get; set; }
public string Comment { get; set; }

Controller action:

[HttpPost]
public IActionResult PostPaybackRequest([FromForm] WellnessPayback payback)
{ 
    if (!ModelState.IsValid) return BadRequest(ModelState);
    // TODO
    return Ok();
}

model in angular:

export interface IWellnessPayback {
  expenseType: string;
  otherActivity: string;
  provider: string;
  requestedAmount: number;
  invoiceFile: File;
  comment: string;
}

method in angular service:

public postPaybackRequest(payback: IWellnessPayback): Observable<boolean> {
  const formData = new FormData();
  for (const prop in payback) {
    if (!payback.hasOwnProperty(prop)) { continue; }
    formData.append(prop , payback[prop]);
  }
  return this._http.post<IOption[]>(`${this._baseUrl}/Me`, formData).pipe(map(x => true));
}

where this._http is an HttpClient.

StepUp
  • 36,391
  • 15
  • 88
  • 148
moi_meme
  • 9,180
  • 4
  • 44
  • 63
0

You have two choices:

  • Pass the image as a base64 string as described here: Angular 2 encode image to base64. The base64 string can be bound to a byte[] property server-side.
  • Use a multipart form request as described here: File Upload In Angular 2?. The form parts can be bound server-side with an IFormFile or List<IFormFile> action parameter.
Mathieu Renda
  • 14,069
  • 2
  • 35
  • 33
  • 1
    I know how to do it when i only want to send a IFormFile as single element https://devblog.dymel.pl/2016/09/02/upload-file-image-angular2-aspnetcore/ But when it is as property of my model and a try to send it as a part of body i don't know how to do it because it is always null. Can I add whole object to let input = new FormData();? I hope that you understand me, that problem is not to send a file by send file as part of whole model. – Stefan Aug 28 '17 at 17:43