Home > Mobile >  Send form data from React to ASP.NET Core API
Send form data from React to ASP.NET Core API

Time:06-08

I editted the whole question because it was very long and confusing.

Clear, concise new question

I was sending all data from my forms as a stringified JSON, but now I need to append a file, so I can no longer do this. How do I send my form data from React to an ASP.NET Core API in a format that allows appending files?

Old question

I have several forms working perfectly: I send the data using fetch from React and receive it correctly as body in my ASP.NET Core API.

However, I need to send files now, and I don't know how to append them since I am just sending all of my content in a strinfified JSON.

fetch("localhost/api/test", {
    method: 'POST',
    headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json'
    },
    body: JSON.stringify(body)
}).then(result => result.json()).then(
    (result) => {
        console.log(result);
    }
);

I tried sending a FormData object built like this instead of the JSON.stringify(body).

let formData = new FormData();
for (var property in body) {
    formData.append(property, body[property]);
}

But when I send this object instead of the stringified JSON I always get null for all the values in ASP.NET Core.

I also tried sending this:

URLSearchParams(data)

And this:

let formBody = [];
for (var property in details) {
    var encodedKey = encodeURIComponent(property);
    var encodedValue = encodeURIComponent(details[property]);
    formBody.push(encodedKey   "="   encodedValue);
}
formBody = formBody.join("&");

And I tried different combinations of headers with every type of data encoding:

  • No headers
  • 'Content-Type': 'multipart/formdata'
  • 'Content-Type': 'application/json'
  • 'Content-Type': 'application/x-www-form-urlencoded'

I also tried getting the data from ASP.NET with both [FromBody] and [FromForm].

I think I have tried every possible combination of all the options I have explained above, with no result. I always get null values in my API.

Edit:

Right now, I am not even trying to send a file. I am trying to successfully send common data in the proper format before trying to attach a file. I don't know if I should change the title of the question.

This is my API code:

[HttpPost]
[Route("login")]
public object Login([FromBody] Credentials cred)
{
    // check credentials
    return CustomResult.Ok;
}

The class Credentials:

public class Credentials
{
    public string Username { get; set; }
    public string Password { get; set; }
}

The object body from React looks like this:

{
    username: "user",
    password: "pass"
}

CodePudding user response:

A bit more time now. (10 fish caught.) I notice from your code you had used the header "multipart/formdata", It should have a hyphen; "multipart/form-data".

On my API I am specifying that it consumes the same type: [Consumes("multipart/form-data")]

I am not clear what the .net core defaults are and whether it should automatically de-serialise the form data but specifying it should rule out any ambiguity.

With my code I am sending a file with some parameters. On the api side it looks like:

    public class FileUpload_Single
    {
        public IFormFile DataFile { get; set; }
        public string Params { get; set; }
    }

    // POST: api/Company (Create New)
    [HttpPost]
    [Authorize(PermissionItem.SimulationData, PermissionAction.Post)]
    [RequestSizeLimit(1024L * 1024L * 1024L)]  // 1 Gb
    [RequestFormLimits(MultipartBodyLengthLimit = 1024L * 1024L * 1024L)] // 1 Gb
    [Consumes("multipart/form-data")]
    public async virtual Task<IActionResult> Post([FromForm] FileUpload_Single data)

.... Then on the client side it looks like:

  let formData = new FormData();
  formData.append("DataFile", file);
  formData.append("Params", JSON.stringify(params));
  fetch(apicall, {
    method: "POST",
    mode: "cors",
    headers: {
      Authorization:
        "Bearer "   (localStorage.getItem("token") || "").replace(/['"] /g, ""),
      Accept: "multipart/form-data",
    },
    body: formData,
  })

With the file coming from

  const changeHandler = (event) => {
    setSelectedFile(event.target.files[0]);
    setIsSelected(true);
  };

(from my React component)

CodePudding user response:

My whole question was a mess and, in my case, the problem was the for loop. However, I will try to explain clearly what I needed because there is a lot of missleading information online about how to submit a form to an API with React.

Solution

Backend

In the backend, accept POST petitions and get the data with FromForm.

[HttpPost]
[Route("login")]
public object Login([FromForm] Credentials cred)
{
    // check credentials
    return CustomResult.Ok;
}

If you bind an object, the properties must have the same name as the ones you are sending from the frontend and must have a public setter.

public class Credentials
{
    public string Username { get; set; }
    public string Password { get; set; }
}

Frontend

Send the data as FormData. To do this, you can follow this tutorial. That way, you won't need to worry about handling input changes and formatting your data before submitting it.

However, if your data is already in a plain JavaScript object, you can transform it in a FormData as shown below.

let formData = new FormData();
Object.keys(data).forEach(function (key) {
    formData.append(key, data[key]);
});

Nonetheless, this is very basic and if you have a complex object (with arrays, nested objects, etc) you will probably need to handle it differently.

Finally, I used fetch to call my API. If you use it, is important to NOT set the Content-Type header, because you will be overwritting the one that fetch automatically chooses for you, which will be the right one in most cases.

fetch("localhost/api/test", {
    method: 'POST',
    headers: {
        'MyHeader': headerValue
        // DON'T overwrite Content-Type header
    },
    body: formData
}).then(result => result.json()).then(
    (result) => {
        console.log(result);
    }
);
  • Related