简体   繁体   中英

Send form data from React to ASP.NET Core API

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"
}

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)

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 . If you need to use credentials, it is probably better to pass them through headers instead of putting them as hidden inputs inside every single form.

[HttpPost]
[Route("test")]
public object Test([FromHeader] string token, [FromForm] MyDataClass data)
{
    // check token
    // do something with data
    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 MyDataClass
{
    public string SomeInfo { get; set; }
    public string SomeOtherInfo { 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 need to handle it differently.

Finally, I used fetch to call my API. If you use it, 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: {
        'Token': "dummy-token"
        // DON'T overwrite Content-Type header
    },
    body: formData
}).then(result => result.json()).then(
    (result) => {
        console.log(result);
    }
);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM