Search code examples
vue.jsasp.net-coremultipartform-data

.NET & Vue API communication through [FromForm]


I'm trying to send a list of object in which contains IFormFile.

Here are my object :

public class ImageGalleryDto
{
    public Guid? PageId { get; set; }
    public int? Order { get; set; }
    public IFormFile? Image { get; set; }
}

My endpoint in .net core :

public async Task<EndpointResult<object>> UpdateImageGallery([FromForm] List<ImageGalleryDto> imageGalleryDto)

My object in vue is exactly same as with this model. And I'm trying to send like this in vue.js

const formData = new FormData();
formData.append("imageGalleryDto", pushToApi);

this.updateImageGallery(formData).then((res) => {....}

Unfortunately, in the controller, the list is empty when it is called.


Solution

  • According to your description, it looks like there is something wrong with your formdata, the formdata should like below, then the asp.net core model binding will auto bind the data to the model inside the web api controller.

                    const formData = new FormData();
                    this.images.forEach((image, index) => {
                        formData.append(`imageGalleryDto[${index}].pageId`, image.pageId);
                        formData.append(`imageGalleryDto[${index}].order`, image.order);
                        formData.append(`imageGalleryDto[${index}].image`, image.image);
                    });
    

    The details example like below:

    Since you have vue.js tag, I use vue.js example

    Client:

    <div id="app">
        <image-upload-form></image-upload-form>
    </div>
    
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.min.js"></script>
    <script>
        Vue.component('image-upload-form', {
            template: `
            <div>
              <form @submit.prevent="uploadImages" enctype="multipart/form-data">
                <div v-for="(image, index) in images" :key="index">
                  <input type="text" v-model="image.pageId" :name="'images[index].pageId'" placeholder="Page ID"/>
                  <input type="number" v-model="image.order" :name="'images[index].order'" placeholder="Order"/>
                  <input type="file" ref="file" :name="'images[index].image'" @change="onFileChange(index,$event)" />
                </div>
                <button type="submit">Upload Images</button>
              </form>
            </div>
          `,
            data() {
                return {
                    images: [{ pageId: '', order: '', image: null }, { pageId: '', order: '', image: null }]
                };
            },
            methods: {
                onFileChange(index, event) {
                        this.images[index].image = event.target.files[0];
                    
                },
                async uploadImages() {
                    const formData = new FormData();
                    this.images.forEach((image, index) => {
                        formData.append(`imageGalleryDto[${index}].pageId`, image.pageId);
                        formData.append(`imageGalleryDto[${index}].order`, image.order);
                        formData.append(`imageGalleryDto[${index}].image`, image.image);
                    });
    
                    try {
                        const response = await fetch('https://localhost:7204/api/values/upload', {
                            method: 'POST',
                            body: formData
                        });
    
                        if (response.ok) {
                            console.log('Images uploaded successfully');
                        } else {
                            console.error('Failed to upload images');
                        }
                    } catch (error) {
                        console.error('Error uploading images', error);
                    }
                }
            }
        });
    
        new Vue({
            el: '#app'
        });
    </script>
    

    Backend:

    [Route("api/[controller]")]
    [ApiController]
    public class ValuesController : ControllerBase
    {
    
        [HttpPost("upload")]
        public async Task<IActionResult> UploadImages([FromForm] List<ImageGalleryDto> imageGalleryDto)
        {
            // Do something with the imageGalleryDtos object
            return new JsonResult("OK");
        }
    

    Result:

    enter image description here