Soheil Alizadeh
Soheil Alizadeh

Reputation: 3066

Send file with JSON Data in ajax request

I want to send a image file to a the Controller but HttpPostedFileBase is null and I enter image: image outside JSON.stringify({}) but not worked. Also, I change contentTypeand see this question and use it answer but my problem not fixed.

var file_data = $("#Image").prop("files")[0];   
var image = new FormData();

image.append("file", file_data);

$.ajax({
        url: '@postUrl',
        method: "POST",
        contentType: 'application/json',
        data:
            JSON.stringify({
                    image: image,
                    isFirst : true,
                    ExternalProjects: ExternalProjects,
                    // more data

            })
       })

Upvotes: 5

Views: 23481

Answers (2)

AuthorProxy
AuthorProxy

Reputation: 8047

The best wat I discovered for myself:

export const convertDataToFormDataFormat = (data, formData = null, keyPrefix = '') => {
  if (!data) {
    return null;
  }

  let currentFormData = formData || new FormData();
  if (Array.isArray(data)) {
    data.forEach((entry, i) => {
      currentFormData = convertDataToFormDataFormat(entry, currentFormData, `${keyPrefix}[${i}].`);
    });

    return currentFormData;
  }

  if (data) {
    Object.entries(data).forEach(([key, value]) => {
      const fullKey = keyPrefix + key;
      if (value === undefined || value === null) {
        currentFormData.append(fullKey, '');
      } else if (value.constructor === File) {
        currentFormData.append(fullKey, value);
      } else if (Array.isArray(value)) {
        currentFormData = convertDataToFormDataFormat(value, currentFormData, `${fullKey}`);
      } else if (value === Object(value)) {
        currentFormData = convertDataToFormDataFormat(value, currentFormData, `${fullKey}.`);
      } else {
        currentFormData.append(fullKey, value);
      }
    });
  }

  return currentFormData;
};

Converts to something like this:

fieild.test1= 'test';
fieild.test2= 'test';
field.arr[0].testField1 = 'testField ';
field.arr[0].testField2 = 'testField ';
field.arr[1].testField = 'testField ';
field.arr[1].testField2 = 'testField ';
field.arr[2].testField = 'testField ';
field.arr[2].testField2 = 'testField ';

Works great for asp.net core 2.0:

[HttpPost]
public async Task<IActionResult> CreateExpense([FromForm] List<SomeModelWithIFormFileField> dto)
{
    ....
}

Upvotes: 1

Patrick Evans
Patrick Evans

Reputation: 42736

You do not put the FormData instance within an object and stringify it. You do the opposite: put your file(s) and other data in the FormData instance.

And as the answer you linked to says change the contentType and processData options to false to tell jQuery not to process the data itself.

var file_data = $("#Image").prop("files")[0];   
var fd = new FormData();

fd.append("file", file_data);
fd.append("isFirst", true);
fd.append("ExternalProjects", ExternalProjects);
$.ajax({
    url: '@postUrl',
    method: "POST",
    contentType: false,
    processData: false,
    data:fd
});

Your data will be in the respective fields: file, isFirst, and ExternalProjects

Upvotes: 7

Related Questions