Problem
To save a customer, an ASP.NET MVC4 Web API application specifies a post method. In the POST request body, the customer is supplied in json format. The properties for the customer parameter in the post method are nil.
How can this be resolved so that the uploaded data is passed as a customer object?
Because I don’t know how to change it in the javascript method that publishes the form, Content-Type: application/x-www-form-urlencoded should be used if at all possible.
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"}
Asked by Andrus
Solution #1
EDIT : 31/10/2017
For Asp.Net Core 2.0, the same code/approach will work. The main distinction is that with asp.net core, both web api and Mvc controllers are combined into a single controller model. So it’s possible that your return type is IActionResult or one of its implementations (Ex :OkObjectResult)
Use
contentType:"application/json"
When you send it, you must use the JSON.stringify method to turn it to a JSON string.
The model binder will then link your class object to the json data.
The code below will suffice (tested)
$(function () {
var customer = {contact_name :"Scott",company_name:"HP"};
$.ajax({
type: "POST",
data :JSON.stringify(customer),
url: "api/Customer",
contentType: "application/json"
});
});
Result
The contentType field informs the server that the data is in JSON format. Model binding will work effectively because we sent a JSON data format.
If you look at the headers of the ajax request, you’ll notice that the Content-Type value is set to application/json.
If you do not specify contentType explicitly, It will use the default content type which is application/x-www-form-urlencoded;
Edited in November 2015 to address further issues noted in the 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 the end point of your web api is
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;
}
}
ASP.NET MVC 6 is the most recent stable version at the time of writing, and in MVC6, both Web api controllers and MVC controllers inherit from Microsoft. Base class for AspNet.Mvc.Controller.
The code below should work perfectly to submit data to the method from the client side.
//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 don’t use the [FromBody] element on the web api method parameter,
[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 only function for flat properties on the model, not those with a complex/another type type. The Id and Name properties will be correctly bound to the parameter m in our scenario, but the Tags property will be empty.
The identical issue will arise if you use the short version, $.post, which will submit the request with the default Content-Type.
$.post("../product/save", model, function (res) {
//res contains the markup returned by the partial view
console.log('res', res);
});
Answered by Shyju
Solution #2
It’s not easy to work with POST in the webapi! I’d like to add anything to the previously correct response.
Will concentrate on POST because dealing with GET is simple. I doubt many people would go looking for a solution to a GET issue with webapis. Anyways..
If your inquiry is, “How can I use custom action method names other than the generic HTTP verbs in MVC Web Api?” – Can you make several posts? – Do you want to post several simple types? – Is it possible to use jQuery to post complicated types?
The following suggestions may be useful:
To utilize Custom Action Methods in Web API, first create a web api route with the following parameters:
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}");
}
After that, you may construct action methods such as:
[HttpPost]
public string TestMethod([FromBody]string value)
{
return "Hello from http post web api controller: " + value;
}
Now, from your browser console, execute the following jQuery.
$.ajax({
type: 'POST',
url: 'http://localhost:33649/api/TestApi/TestMethod',
data: {'':'hello'},
contentType: 'application/x-www-form-urlencoded',
dataType: 'json',
success: function(data){ console.log(data) }
});
Second, if you want to make many posts, It’s simple: create many action methods and use the [HttpPost] attrib to decorate them. To assign custom names, etc., use [ActionName(“MyAction”)]. In the fourth point below, we’ll discuss jQuery.
Third, it is not possible to upload numerous SIMPLE kinds in a single action. Furthermore, even a single simple type must be posted in a specific format (apart from passing the parameter in the query string or REST style). This was the point where I spent over 5 hours beating my head against Rest Clients (like Fiddler and Chrome’s Advanced REST client plugin) and searching the web for answers before finding the following URL. I’ll quote the necessary content because the link may expire!
Content-Type: application/x-www-form-urlencoded
in the request header and add a = before the JSON statement:
={"Name":"Turbo Tina","Email":"na@Turbo.Tina"}
PS: Noticed the peculiar syntax?
http://forums.asp.net/t/1883467.aspx?The+received+value+is+null+when+I+try+to+Post+to+my+Web+Api
Anyway, let’s move on from that story. Now let’s move on:
Fourth, when publishing complex kinds with jQuery, $.ajax() will, of course, play an important role:
Assume the action method takes a Person object with a name and an id. So, here’s what javascript says:
var person = { PersonId:1, Name:"James" }
$.ajax({
type: 'POST',
url: 'http://mydomain/api/TestApi/TestMethod',
data: JSON.stringify(person),
contentType: 'application/json; charset=utf-8',
dataType: 'json',
success: function(data){ console.log(data) }
});
And the activity will be as follows:
[HttpPost]
public string TestMethod(Person person)
{
return "Hello from http post web api controller: " + person.Name;
}
Everything above worked for me!! Cheers!
Answered by Vaibhav
Solution #3
I was simply messing about with this and came up with an interesting result. Assume your C# class has the following public properties:
public class Customer
{
public string contact_name;
public string company_name;
}
Then, as suggested by Shyju, use the JSON.stringify technique and call it something like this:
var customer = {contact_name :"Scott",company_name:"HP"};
$.ajax({
type: "POST",
data :JSON.stringify(customer),
url: "api/Customer",
contentType: "application/json"
});
If, on the other hand, you define your class’s getters and setters like follows:
public class Customer
{
public string contact_name { get; set; }
public string company_name { get; set; }
}
Then you can call it something much more straightforward:
$.ajax({
type: "POST",
data :customer,
url: "api/Customer"
});
This makes use of the following HTTP header:
Content-Type:application/x-www-form-urlencoded
I’m not sure what’s going on here, but it appears to be a framework bug (feature?). The different binding methods are presumably calling distinct “adapters,” and while the application/json adapter works with public properties, the form encoded data adapter does not.
However, I have no notion what would be considered excellent practise.
Answered by Andy
Solution #4
To receive the string in JSON format, use JSON.stringify(). Make sure to supply the following attributes to the AJAX call:
To make an ajax post request to an asp.net web API, use the following jquery code:
Answered by Dilip Nannaware
Solution #5
Check to see if your WebAPI service expects a strongly typed object with the same structure as the JSON you’re passing. Also, make sure the JSON you’re POSTing is stringified.
My JavaScript (using AngluarJS) is as follows:
$scope.updateUserActivity = function (_objuserActivity) {
$http
({
method: 'post',
url: 'your url here',
headers: { 'Content-Type': 'application/json'},
data: JSON.stringify(_objuserActivity)
})
.then(function (response)
{
alert("success");
})
.catch(function (response)
{
alert("failure");
})
.finally(function ()
{
});
My WebAPI Controller is as follows:
[HttpPost]
[AcceptVerbs("POST")]
public string POSTMe([FromBody]Models.UserActivity _activity)
{
return "hello";
}
Answered by scottyj
Post is based on https://stackoverflow.com/questions/20226169/how-to-pass-json-post-data-to-web-api-method-as-an-object