I would like to understand a little better about WebApi in Net and how is the correct way to called it with ajax. Little of info about my development environment: I am using .net 4.0 and visual studio 2010 and Jquery.
Model:
public class TestForm
{
public string FirstName { get; set; }
}
WebApi:
public class TestpController : ApiController
{
[HttpPost]
public HttpResponseMessage Post(TestForm form)
{
string jose = "jose";
return Request.CreateResponse(HttpStatusCode.OK, "yay");
}
}
Client side:
V1 (doesnt work, return error 405 ):
$.ajax({
url: "http://xxx/api/Testp",
type: "POST",
data: JSON.stringify({ FirstName: "Jose" }),
dataType: 'json',
contentType: "application/json; charset=utf-8",
success: function(data) {
console.log("success");
},
error: function (xhr, errorType, exception) {
console.log("error");
}
});
V2 (works):
$.ajax({
url: "http://xxx/api/Testp",
type: "POST",
data: { FirstName: "Jose" },
dataType: 'json',
success: function(data) {
console.log("success");
},
error: function (xhr, errorType, exception) {
console.log("error");
}
});
Why do I get an error when I add contentType: "application/json; charset=utf-8"
and change the data to JSON.stringify({ FirstName: "Jose" })
, but it works when I removed the content type and send a object in data option.
Short answer lies in the output of these alerts:
alert(JSON.stringify({FirstName :"Jose"}));
alert({FirstName :"Jose"});
The first one gives you a string, the second one gives you an object.
Your method:
public HttpResponseMessage Post(TestForm form)
Accepts an object and not a string. So when you post a string, .NET Framework is not able to find a method which can process a string, hence returns 405.
The Problem you are encountering seems to be jQuery preflight.
If you take a look at the Headers of your request you'll see that in V1 the Http Method used is actually OPTIONS. That is because jQuery does only allow certain values for the Content-Type Header.
@McBoman gave a good overview on this, at the linked source. You may also want to read up on Cross Origin Resource Sharing (Cors) for example this.
You need to add a Function that answers to [HttpOptions]
and explicitly tells the preflight-request that a certain "custom"-Header is allowed or in the case of cross-origin request allowing the originating domain. You would need to adapt the below Function to your needs, taking the info preflight provides you with.
[HttpOptions]
public HttpResponseMessage Options() {
var response = request.CreateResponse(HttpStatusCode.OK);
response.Headers.Add("access-control-allow-origin", "*");
response.Headers.Add("access-control-allow-headers", "content-type");
return response;
}
Hope that helps you.