Search code examples
asp.net-coreasp.net-core-webapimultipartform-dataasp.net-core-3.1

Unexpected behaviour when uploading multiple files using multipart/form-data media type in .NET Core Web API?


I am using .NET core 3.1 in my project where I have a situation to upload multiple files. Below is my model:

public class ProductImageDetailsDto
{
    [Display(Name = "product image")]
    [AllowedExtensions(new string[] { ".jpg", ".png" })]
    public IFormFile ProductImage { get; set; }
}

Below is my WebAPI, in which I am accepting List<ProductImageDetailsDto> as a parameter:

    [HttpPut("UpdateProductImagesByProductId/{id}")]
    public async Task<IActionResult> UpdateProdutImagesByProductId(Guid id, [FromForm] List<ProductImageDetailsDto> productImages)
    {
        ApiResponseModel<string> apiResponse = await _productDetailServices.UpdateProductImagesByProductIdAsync(id, productImages, new Guid(UserId));
        return Ok(apiResponse);
    }

When I pass data from postman or swagger, nothing is being received on the API side and productImages parameter has count = 0. I am passing the data from the postman like this:

productImages[0].ProductImage :  file
productImages[1].ProductImage :  file1

But if I modify my ProductImageDetailsDto class and add more field let's say IsDefault like below:

public class ProductImageDetailsDto
{
    [Display(Name = "product image")]
    [AllowedExtensions(new string[] { ".jpg", ".png" })]
    public IFormFile ProductImage { get; set; }
    public bool IsDefault { get; set; }
}

And if I pass data from postman like this:

productImages[0].ProductImage :  file
productImages[0].IsDefault:      false
productImages[1].ProductImage :  file1
productImages[1].IsDefault:      true

everything seems to be working fine and I am receiving data i.e both ProductImage and IsDefault on the API side.

So what's the issue if I keep only IFormFile field in ProductImageDetailsDto. Is there anything I am missing or doing something wrong? Thanks in advance.

Note: I don't want to take List<IFormFile> or IFormFileCollection as parameter type in API as I want to validate the images using custom validator [AllowedExtension], that's why I have created IFormFile property inside the Model and accepting List<ProductImageDetailsDto> as a parameter.


Solution

  • Change your code like below if you want to pass only productImages[0].ProductImage,remove [ApiController] and [FromForm]:

    // [ApiController]
    [Route("[controller]")]
    public class TestController : ControllerBase
    {     
        [HttpPut("UpdateProductImagesByProductId/{id}")]
        public async Task<IActionResult> UpdateProdutImagesByProductId(Guid id, List<ProductImageDetailsDto> productImages)
        {
    
            return Ok();
        }
    }
    

    Result:

    enter image description here

    Update:

    If you want to maintain [ApiController] and custom validation,add the custom attribute in the action and remove [FromForm] like below:

    public async Task<IActionResult> UpdateProdutImagesByProductId(Guid id,[AllowedExtensions(new string[] { ".jpg", ".png"})] List<IFormFile> files)
    

    Result: enter image description here