Search code examples
asp.net-coreasp.net-web-apifile-uploadcreate-react-appmultipartform-data

Cannot upload a file in Asp.Net Core 3.1 API


In a React App:

const onInputFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const files = e.target.files;
    if (!files || files.length === 0) {
        return;
    }

    const file = files[0];
    const formData = new FormData();
    formData.append("file", file);
    
    const uri = "path/to/my/endpoint/myc/12/upload";
    const fetchOptions = {
        method: "POST",
        headers: [["Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"]],
        mode: "cors",
        body: formData
    };
    
    fetch(uri, fetchOptions).then(res => console.log(res));
};

return (
    <input
        onChange={onInputFileChange}
        type="file"
        accept={".xslx"}
    />
);

I am sending an Excel file. I have the following controller:

[HttpPost("myc/{id}/upload")]
//[Consumes("multipart/form-data")] // This line is commented intentionally
public ActionResult UploadExcelFile(string id)
{
    var form = this.Request.Form; // Exception here!!!
    return Ok();
}

When I set a breakpoint in the method (beginning), I see it is hit. When I step further in the first line, an exception is thrown when reading Form:

System.InvalidOperationException: 'Incorrect Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'

Attempt I

If I remove the comment in the attribute Consumes, I never get to the method; instead I get a 415 Unsupported media Type.

Attempt II

If I set the controller's Consumes and the request's Content-Type both to: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, I get the same error:

System.InvalidOperationException: 'Incorrect Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'

Attempt III

If I change the controller like this:

[HttpPost("myc/{id}/upload")]
//[Consumes("multipart/form-data")]
public ActionResult UploadExcelFile(string id, IFormFile file)
{
    var form = this.Request.Form;
    return Ok();
}

I get a 400 Bad Request and do not hit the method.


How exactly am I supposed to make this work?


Solution

  • Just omit Content-Type header in request and browser will set a correct one for you. Since correct value for FormData is Content-Type: multipart/form-data; boundary=something you need to let browser to set valid boundary value for you.

    const file = files[0];
    const formData = new FormData();
    formData.append("file", file);
    
    const uri = "path/to/my/endpoint/myc/12/upload";
    const fetchOptions = {
        method: "POST",
        mode: "cors",
        body: formData
    };
    
    fetch(uri, fetchOptions).then(res => console.log(res));