I'm trying to perform a cross-domain POST request to an ASP.NET MVC controller action. This controller action accepts & uses various parameters. The problem is that when the preflight request happens, the controller action actually attempts to execute & because the OPTIONS request doesn't pass any data, the controller action throws out a 500 HTTP error. If I remove the code that uses the parameter, or the parameter itself, the entire request chain is completed successfully.
An example of how this is implemented:
Controller Action
public ActionResult GetData(string data)
{
return new JsonResult
{
Data = data.ToUpper(),
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
Client-side code
<script type="text/javascript">
$(function () {
$("#button-request").click(function () {
var ajaxConfig = {
dataType: "json",
url: "http://localhost:8100/host/getdata",
contentType: 'application/json',
data: JSON.stringify({ data: "A string of data" }),
type: "POST",
success: function (result) {
alert(result);
},
error: function (jqXHR, textStatus, errorThrown) {
alert('Error: Status: ' + textStatus + ', Message: ' + errorThrown);
}
};
$.ajax(ajaxConfig);
});
});
</script>
Now, whenever the preflight request happens, it returns a 500 HTTP code, because the "data" parameter is null, seeing as the OPTIONS request doesn't pass any values.
The server application has been set up in my local IIS on port 8100 & the page running the client-side code is set up on port 8200 to mimic the cross-domain calls.
I have also configured the host (on 8100) with the following headers:
Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Methods: POST, GET
Access-Control-Allow-Origin: http://localhost:8200
One workaround I had found, was to check the HTTP method that executes the action & if it's a OPTIONS request to just return blank content, otherwise execute the action code. Like so:
public ActionResult GetData(string data)
{
if (Request.HttpMethod == "OPTIONS") {
return new ContentResult();
} else {
return new JsonResult
{
Data = data.ToUpper(),
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
}
But this approach feels very clunky to me. I considered adding this sort of logic to an Attribute, but even this would mean decorating every action that will get called using CORS with it.
Is there a more elegant solution to getting this functionality to work?
So I have found a solution that works. For each request, I check whether it's a CORS request & whether the request is coming in with the OPTIONS verb, indicating that it's the preflight request. If it is, I just send an empty response back (which only contains the headers configured in IIS of course), thus negating the controller action execution.
Then if the client confirms it's allowed to perform the request based on the returned headers from preflight, the actual POST is performed & the controller action is executed. And example of my code:
protected void Application_BeginRequest()
{
if (Request.Headers.AllKeys.Contains("Origin", StringComparer.OrdinalIgnoreCase) &&
Request.HttpMethod == "OPTIONS") {
Response.Flush();
}
}
As mentioned, this worked for me, but if anyone knows of a better way, or of any flaws in my current implementation, I would appreciate to hear about them.