Send string in body as a POST REST call (javascript to Asp.Net Core)

14.2k views Asked by At

I have a simple back-end API written in Asp.Net Core that receives a string:

        [HttpPost]
        public IResult Post([FromBody] string value)
        {
            //do something with value...
        }

And my front-end javascript looks like this:

      const request = {
        method: 'POST',
        mode : "cors",
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ amount, currency })
      };
      const response = await fetch(link, request);
      const data = await response.json();

It seems all easy peasy, but I get the following errors:
"Unexpected character encountered while parsing value: {. Path '', line 1, position 1."
"The value field is required."

The problem is in the body, that is sent as JSON object:
{ "amount":123, "currency":"eur"}

Apparently the parsing creates problems.
If, with Postman, I send this string inside the body:
"{ \"amount\":123, \"currency\":\"eur\"}"

Everything works!

If I send it via javascript, it doesn't :(

So, my question is: clearly c# is messing up with the type of the data in the body. It is expecting a string but it is receiving a JSON (even though, JSON.stringfy makes a string, but somehow it seems parsed back to JSON somewhere in between).

Can I change the type on C# to something like JSON and everything will automagically work? Is there a way to send a JSON looking string via javascript without this unwanted conversion in between?


Additional info:

@StrikeGently way does not work. I get an error message saying that only 1 parameter can be passed with the [FromBody] attribute.

@joacoleza way might work, but I would like to avoid it as it would fill my code with tens of small classes describing the input of the function.

This works. But my eyes bleed:

        body:"'" + JSON.stringify({amount, currency}) + "'"

Is this the most elegant solution to pass a string?

3

There are 3 answers

0
Alvin Sartor On BEST ANSWER

Even though @joacoleza's answer does work, it was not feasible in one of my cases (the object that I am receiving is huge (~200 fields) and I only need to extract 5. Also it might change quite often and I'd have to adjust my object even though I am not really touched by the changes.

I finally found the solution myself:

As already said, .Net tries to parse the content of the body to the requested object:

public ActionResult Post([FromBody] string value)

This requires a string object. If we want to send a JSON and then parse it, we can send it in this way: '{"field":"value", "field2":"value2"}'

But if we do not control the content of the body in the request and we are receiving a X object (or different object that we might want to parse in run-time) we just need to change the type of the function argument to JObject:

public ActionResult Post([FromBody] JObject value)

The parsed JObject will contain the whole structure of the JSON, but it will still give us enough freedom to do whatever we want with the raw version, without having to cast it to a POCO just for the transition: var amount = value["amount"];

This is what I was looking for.

1
Strikegently On

It's expecting a string for value but you're giving it an object. You can either change the parameters of the method to accept an object with amount and currency properties or change the parameters of the method to accept two variables of the same name.

[HttpPost]
public IResult Post([FromBody] int amount, [FromBody] string currency)
{
    //do something
}
3
joacoleza On

Try doing it this way.

Send the request like this:

const request = {
    method: 'POST',
    mode : "cors",
    headers: { 'Content-Type': 'application/json' },
    body: { amount: 100, currency: 'USD' })
  };
const response = await fetch(link, request);
const data = await response.json();

And define a class that can be binded to the body you are sending:

public class MyClass
{
    public int Amount { get; set; }
    public string Currency  { get; set; }
}

And use that class as parameter of the POST method:

[HttpPost]
public IResult Post([FromBody] MyClass data)
{
    //do something with value...
}