Why your [FromBody] parameter is always NULL

For some reason I always forget the workings of Web API parameter binding. For the umpteenth time my [FromBody] parameter is NULL. Time to sort things out and write it down.

A good start to read more about the parameter binding in Web API is Parameter Binding in ASP.NET Web Api

IMHO the [FromBody] explanation in the article is little bit too simplistic though, as I didn't get my code to work.

Ok so this was my initial request, that did not work:

$.ajax({
    type: "POST",
    contentType: "application/json; charset=utf-8",
    url: "api/discount/saveEmailForDiscount",
    data: {email: "some@email.com"}
});

and the C# code:

[HttpPost, Route("api/discount/saveEmail")]
public IHttpActionResult SaveEmailForDiscount([FromBody] string email)  
{
    //do something with e-mail
    return Ok(email);
}

To force Web API to read a "simple" type from the request body you need to add the [FromBody] attribute to the parameter.

Web API reads the response body at most once, so only one parameter of an action can come from the request body. If you need to get multiple values from the request body, define a complex type.

But still the value of email is NULL.

The JavaScript code is part of generic method we use, so that's why the content-type is set to application/json; charset=utf-8. Although the example in the article mentioned above also uses the content-type application/json, this is the source of our problem.

The default content-type of an AJAX request is application/x-www-form-urlencoded; charset=UTF-8. So if we leave the content-type out of it, or specifying it with application/x-www-form-urlencoded; charset=UTF-8 it should be working right? Well... No. Apparently the value should be formatted like this:

=value

Knowing this gives the final JavaScript code which will work:

$.ajax({
   type: "POST",
    contentType: "application/x-www-form-urlencoded; charset=UTF-8", //this could be left out as it is the default content-type of an AJAX request
    url: "api/discount/saveEmailForDiscount",
    data: =+"some@email.com"
});

One last thing to mention is the remark on the Asp.Net site:

Before sending a simple type, consider wrapping the value in a complex type instead. This gives you the benefits of model validation on the server side, and makes it easier to extend your model if needed.