ASP.NET MVC4 Web API application defines post method to save customer. Customer is passed in json format in POST request body. Customer parameter in post method contains null values for properties.
How to fix this so that posted data will passed as customer object ?
If possible Content-Type: application/x-www-form-urlencoded should used since I dont know how to change it in javascript method which posts form.
Controller:
public class CustomersController : ApiController {
public object Post([FromBody] Customer customer)
{
return Request.CreateResponse(HttpStatusCode.OK,
new
{
customer = customer
});
}
}
}
public class Customer
{
public string company_name { get; set; }
public string contact_name { get; set; }
}
Request:
POST http://localhost:52216/api/customers HTTP/1.1
Accept: application/json, text/javascript, */*; q=0.01
X-Requested-With: XMLHttpRequest
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
{"contact_name":"sdfsd","company_name":"ssssd"}
EDIT : 31/10/2017
The same code/approach will work for Asp.Net Core 2.0 as well. The major difference is, In asp.net core, both web api controllers and Mvc controllers are merged together to single controller model. So your return type might be IActionResult
or one of it's implementation (Ex :OkObjectResult
)
Use
contentType:"application/json"
You need to use JSON.stringify
method to convert it to JSON string when you send it,
And the model binder will bind the json data to your class object.
The below code will work fine (tested)
$(function () {
var customer = {contact_name :"Scott",company_name:"HP"};
$.ajax({
type: "POST",
data :JSON.stringify(customer),
url: "api/Customer",
contentType: "application/json"
});
});
Result
contentType
property tells the server that we are sending the data in JSON format. Since we sent a JSON data structure,model binding will happen properly.
If you inspect the ajax request's headers, you can see that the Content-Type
value is set as application/json
.
If you do not specify contentType explicitly, It will use the default content type which is application/x-www-form-urlencoded;
Edit on Nov 2015 to address other possible issues raised in comments
Let's say you have a complex view model class as your web api action method parameter like this
public class CreateUserViewModel
{
public int Id {set;get;}
public string Name {set;get;}
public List<TagViewModel> Tags {set;get;}
}
public class TagViewModel
{
public int Id {set;get;}
public string Code {set;get;}
}
and your web api end point is like
public class ProductController : Controller
{
[HttpPost]
public CreateUserViewModel Save([FromBody] CreateUserViewModel m)
{
// I am just returning the posted model as it is.
// You may do other stuff and return different response.
// Ex : missileService.LaunchMissile(m);
return m;
}
}
At the time of this writing, ASP.NET MVC 6 is the latest stable version and in MVC6, Both Web api controllers and MVC controllers are inheriting from Microsoft.AspNet.Mvc.Controller
base class.
To send data to the method from client side, the below code should work fine
//Build an object which matches the structure of our view model class
var model = {
Name: "Shyju",
Id: 123,
Tags: [{ Id: 12, Code: "C" }, { Id: 33, Code: "Swift" }]
};
$.ajax({
type: "POST",
data: JSON.stringify(model),
url: "../product/save",
contentType: "application/json"
}).done(function(res) {
console.log('res', res);
// Do something with the result :)
});
If you do not decorate the web api method parameter with [FromBody]
attribute
[HttpPost]
public CreateUserViewModel Save(CreateUserViewModel m)
{
return m;
}
And send the model(raw javascript object, not in JSON format) without specifying the contentType property value
$.ajax({
type: "POST",
data: model,
url: "../product/save"
}).done(function (res) {
console.log('res', res);
});
Model binding will work for the flat properties on the model, not the properties where the type is complex/another type. In our case, Id
and Name
properties will be properly bound to the parameter m
, But the Tags
property will be an empty list.
The same problem will occur if you are using the short version, $.post
which will use the default Content-Type when sending the request.
$.post("../product/save", model, function (res) {
//res contains the markup returned by the partial view
console.log('res', res);
});