ASP.NET MVC 4 Web API has limited support to map POST form variables to simple parameters of a Web API method. Web API does not deal with multiple posted content values, you can only post a single content value to a Web API Action method. This post explains the different ways to pass multiple parameters to Web API method.
Suppose You have following Web API method:
public HttpResponseMessage PostProduct(int Id,String Name,String Category, decimal Price)
{
//...
}
and you are trying to call using
Unfortunately, Web API can't handle this request and you'll get error. But if you pass parameters using query string, It'll work: But it's not good solution and not applicable for complex objects. So here are the different ways to do it. Model: Create a model having all parameters to be passed Controller: Use the model as argument type in the method jQuery: OR ASP.NET Web API provides to create a custom Parameter Binding to extend the functionality and allows you to intercept processing of individual parameters. Check Rick's Post to implement it. Web API now uses JSON.NET for it's JSON serializer, So you can use the JObject class to receive a dynamic JSON result, cast it properly or parse it into strongly typed objects. OR You can directly parse it into strongly typed class: You can define FormDataCollection type argument and read parameter one by one manually using .Get() or .GetValues() methods (for multi-select values). data: { Id: 2012, Name: 'test', Category: 'My Category', Price: 99.5 }, For above data: We have seen to access multiple parameters from query string easily. It's very helpful when you have to pass Model with additional parameters. So the additional parameters can be passed using query string. Controller: jQuery: You can parse your query string explicitly in method If you have too many query string values to push into parameters. Now, the next question is how to return multiple parameters. First thing is to use Model having all parameters and return its instance, but each time we can't create model for each return type. If all parameters have same data-type then we can create and return a collection. But it might be different data-types. The simplest solution is use dynamic return type. Here is the response: Share your opinion how you are passing multiple parameters to Web API. Hopefully, this behavior can be enabled in future release without being a breaking change.
$.ajax({
url: 'api/products',
type: 'POST',
data: { Id: 2012, Name: 'test', Category: 'My Category', Price: 99.5 },
dataType: 'json',
success: function (data) {
alert(data);
}
});
$.ajax({
url: 'api/products?Id=2012&Name=test&Category=My%20Category&Price=99.5',
type: 'POST',
dataType: 'json',
success: function (data) {
alert(data);
}
});
Using Model Binding:
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public string Category { get; set; }
public decimal Price { get; set; }
}
public HttpResponseMessage PostProduct(Product item)
{
item = repository.Add(item);
var response = Request.CreateResponse<Product>(HttpStatusCode.Created, item);
string uri = Url.Link("DefaultApi", new { id = item.Id });
response.Headers.Location = new Uri(uri);
return response;
}
$.ajax({
url: 'api/products',
type: 'POST',
data: { Id: 2012, Name: 'test', Category: 'My Category', Price: 99.5 },
dataType: 'json',
success: function (data) {
...
}
});
var product = {
Id: 2012, Name: 'test', Category: 'My Category', Price: 99.5
}
$.ajax({
url: 'api/products',
type: 'POST',
data: JSON.stringify(product),
dataType: 'json',
contentType: "application/json",
success: function (data) {
}
});
Using Custom Parameter Binding:
JObject:
public HttpResponseMessage PostProduct(JObject data)
{
dynamic json = data;
Product item = new Product() {
Id = json.Id,
Name = json.Name,
Category = json.Category,
Price =json.Price
};
item = repository.Add(item);
var response = Request.CreateResponse<Product>(HttpStatusCode.Created, item);
string uri = Url.Link("DefaultApi", new { id = item.Id });
response.Headers.Location = new Uri(uri);
return response;
}
public HttpResponseMessage PostProduct(JObject data)
{
Product item = data.ToObject<Product>();
item = repository.Add(item);
var response = Request.CreateResponse<Product>(HttpStatusCode.Created, item);
string uri = Url.Link("DefaultApi", new { id = item.Id });
response.Headers.Location = new Uri(uri);
return response;
}
FormDataCollection:
public HttpResponseMessage PostProduct(FormDataCollection data)
{
Product item = new Product() {
Id = Convert.ToInt32(data.Get("Id")),
Name = data.Get("Name"),
Category = data.Get("Category"),
Price = Convert.ToDecimal(data.Get("Price"))
};
item = repository.Add(item);
var response = Request.CreateResponse<Product>(HttpStatusCode.Created, item);
string uri = Url.Link("DefaultApi", new { id = item.Id });
response.Headers.Location = new Uri(uri);
return response;
}
Query String:
public HttpResponseMessage PostProduct(Product item, string criteria)
{
//...
}
$.ajax({
url: 'api/products?criteria=full',
type: 'POST',
data: JSON.stringify(product),
dataType: 'json',
contentType: "application/json",
success: function (data) {
}
});
public HttpResponseMessage PostProduct(Product item)
{
var queryItems = Request.RequestUri.ParseQueryString();
string criteria = queryItems["criteria"];
//...
}
Return Multiple Parameters:
public dynamic GetProducts()
{
var products = repository.GetAll() as IEnumerable<Product>;
return new
{
Products = products,
Criteria = "full"
};
}