How to upload an IFormFile with additional parameters

Viewed 4110

I have an existing API, that is reading data from the request body:

[HttpPost]
public async Task<IActionResult> Post([FromBody] CreateVm vm)
{
    if (!ModelState.IsValid) return BadRequest();
    var result = await _service.CreateAsync(vm);
    return Ok(result);
}

A new requirement came in, requesting that the client, wants to submit an image along with the view model. My first thought was to attach an IFormFile to the request, handle it in a different service and move on:

public async Task<IActionResult> Post([FromBody] CreateVm vm, IFormFile file) { /* ... */}

The result of this approach is, that I am getting a status code 415 "Unsupported Media Type" back.

Using postman I've tried setting the Content-Type to multipart/form-data, to no avail.

Is this approach somehow possible, or do I need to add a byte[] property to the viewmodel and parse the image from there?

2 Answers

I think form-data request with [FromForm] tag should work for you.

using Microsoft.AspNetCore.Http;

public class CarModelPostDTO {
    public string Name { get; set; }
    public IFormFile Image { get; set; }
}
[HttpPost("api/car")]
public ActionResult Car([FromForm]CarModelPostDTO carDto)
{
    // Getting Name
    string name = carDto.Name;
    // Getting Image
    var image = carDto.Image;
    // Saving Image on Server
    if (image.Length > 0) {
        using (var fileStream = new FileStream(image.FileName, FileMode.Create)) {
            image.CopyTo(fileStream);
        }
    }
    return Ok(new { status = true, message = "Car created successfully"});
}

This is a complete tutorial.

I'm assuming that since this previously worked before the new requirement of uploading a file that you are sending JSON. (In the future, it would be helpful if you showed how you're making the request as well.)

Files can be "uploaded" via JSON, but they must be sent in a format that can be included in a JSON object, namely either an JS int array or a Base64-encoded string. ASP.NET Core can handle either, and will bind the value to a byte[].

Without the code that's making the request, it's hard to give you much more guidance than that, but you essentially just need to add a byte[] property to your view model, and then when making the request, read the file data and write it to the JSON as an int array or Base64-encoded string, corresponding to that property name. If you're making the request via JavaScript, for example, you can use the File API to get the data for the file in the upload input.

IFormFile is only for multipart/form-data encoded requests, and you can't mix and match request body encodings when using the modelbinder. Therefore, you'd have to either stop using JSON or send the file in the JSON object, as described above, instead of using IFormFile.

Related