I have spent a bunch of time "fighting" with WebAPI CORS when suddenly I have understood that the problem is in AJAX call. This request executes successfully:
$.ajax({
url: "myserver:8081/User/Get",
data: {
"Id": 12
},
type: "POST",
dataType: "json",
// contentType: "application/json; encoding=utf-8"
});
According to jQuery.ajax() documentation,
For cross-domain requests, setting the content type to anything other than application/x-www-form-urlencoded, multipart/form-data, or text/plain will trigger the browser to send a preflight OPTIONS request to the server.
Browser is preflighting the request to look for CORS headers and discover if server allows cross-domain requests and making a real request is safe. If the request is acceptable, it will then send the real request.
A browser sends a preflight request is:
- HTTP method is not
GET, POST or HEAD;
- or if
Content-Type is not application/x-www-form-urlencoded, multipart/form-data or text/plain;
- or if any custom HTTP headers are set.
So, Chrome sends OPTIONS "preflight" request. Insofar as I allow only POST and GET requests at the server, the browser thinks that it is a CORS violation and denies request.
This StackOverflow question is directly related to this question and explains what is "preflight" request and why does a browser need to send it.
The solution was as simple as the problem cause - don't specify Content-Type in cross-domain AJAX calls.
If you need to specify custom headers or Content-Type for your requests, you can implement a specal handler which will allow preflight requests. This StackOverflow article describes how to do this.
I hope that it will help someone to save time.