1

I have an <input type='file' /> array of attachments that I post to an API, but I'm getting the files array param empty, what am I missing? Am I declaring the correct type (IEnumerable<IFormFileCollection> files) on the api?

The query string parameters are passing fine.

const  attachments  = Array.from(fileList);

const files = attachments;

const result = await apiPost(`api/attachments/addAttachments?request=${request}&&ticketId=${ticketId}`, files, {
      headers: { 'Content-Type': 'multipart/form-data' },
    });

And the API:

[HttpPost]
[Route("attachments")]
public async Task<string> addAttachments(string request, int ticketId, [FromBody]IEnumerable<IFormFileCollection> files)
{...}

enter image description here

apiPost:

import { AdalConfig, adalFetch } from 'react-adal';

export const apiFetch: <T>(url: string, options?: object) => Promise<T> = (
  url: string,
  options: object,
) => adalFetch(authContext, adalConfig.endpoints.api, axios, url, options);

export const apiPost = async <T>(url: string, data: object): Promise<T> => {
  const options = {
    method: 'post',
    data,
    config: {
      headers: {
        'Content-Type': 'application/json',
      },
    },
  };
  return apiFetch(url, options);
};
Liam
  • 27,717
  • 28
  • 128
  • 190
user3378165
  • 6,546
  • 17
  • 62
  • 101
  • Is this angular? – Liam Jun 03 '19 at 11:01
  • @Liam no, it's not – user3378165 Jun 03 '19 at 11:04
  • Maybe this can help you out: https://stackoverflow.com/questions/10320232/how-to-accept-a-file-post – Krisztián Balla Jun 03 '19 at 11:09
  • It is possible that I see this the wrong way but `Array.from(fileList)` does not return an object that could be destructured using `{ attachments }`. – Lukas Möller Jun 03 '19 at 11:18
  • 2
    What’s `apiPost`? – Ry- Jun 03 '19 at 11:24
  • @Ry- please see my edited question. – user3378165 Jun 03 '19 at 11:27
  • 1
    `apiPost` takes two arguments, and the only place you’re passing `files` is as the third argument…? – Ry- Jun 03 '19 at 11:32
  • What's `adalFetch`?! Please create a [Minimal, Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example) of your problem – Liam Jun 03 '19 at 11:57
  • @Ry- I removed the first parameter and now just trying to pass the `files` array but it still comes up empty – user3378165 Jun 04 '19 at 06:27
  • @Liam Please see my edited question. – user3378165 Jun 04 '19 at 06:28
  • So this is a react application then?! It would really, really help if you'd actually explain what technology your trying to use here instead of drip feeding pieces of information into the question..Not to mention that this seems to be the third iteration of this question you've asked. – Liam Jun 04 '19 at 07:56
  • try [FromForm] instead of [FromBody] in the API files variable – JavierFromMadrid Jun 04 '19 at 07:59
  • 1
    Your content type is wrong, you need to use `multipart/form-data` to upload files. You can't upload files using `application/json` it doesn't support file uploading. [This question](https://stackoverflow.com/questions/51233528/how-to-do-a-rest-api-post-request-with-fileupload-to-an-azure-ad-protected-rest/51319039) seems to cover everything you need – Liam Jun 04 '19 at 08:02

1 Answers1

0

Thanks to the above comments (especially thanks to @Liam for the excellent example he referred me to) I was able to figure it out:

const files = { ...attachments };

const data = new FormData();
// Append files to form data
for (let i = 0; i < attachments.length; i++) {
  data.append('files', files[i], files[i].name);
}

const { result } = apiPost(`api/attachments/addAttachments?request=${request}&ticketId=${ticketId}`, data, {
  headers: { 'Content-Type': 'multipart/form-data' },
});

I changed the apiPost method to get a header param:

export const apiPost = async <T>(url: string, data: object, headers: object): Promise<T> => {
  const options = {
    method: 'post',
    data,
    config: {
      headers: headers || {
        'Content-Type': 'application/json',
      },
    },
  };
  console.log(data);
  console.log(options);
  return apiFetch(url, options);
};

And finally the api controller:

[HttpPost]
[Route("attachments")]
public async Task<string> addAttachments(string request, int ticketId, IEnumerable<IFormFile> files)
user3378165
  • 6,546
  • 17
  • 62
  • 101