As part of my work environment we need to support IE8, but would like to move forward with technology, specifically CORS.
I'm having trouble posting complex objects to a cors service in ie8. The object is null. Below are the steps to reproduce. If needed i can upload the project to github.
I've created a new mvc4 project. Added a API Controller. And made the following changes.
To Support preflight complex cors calls (global.asax):
protected void Application_BeginRequest()
{
//This is needed for the preflight message
//https://stackoverflow.com/questions/13624386/handling-cors-preflight-requests-to-asp-net-mvc-actions
if (Request.Headers.AllKeys.Contains("Origin") && Request.HttpMethod == "OPTIONS") { Response.Flush(); }
}
Source: Handling CORS Preflight requests to ASP.NET MVC actions
To Support text/plain (ie8 only sends text/plain with cors)(global.asax):
protected void Application_Start()
{
//This is needed to support text/plain
HttpConfiguration config = GlobalConfiguration.Configuration;
config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/plain"));
config.Formatters.Remove(config.Formatters.FormUrlEncodedFormatter);
config.Formatters.Remove(config.Formatters.XmlFormatter);
...
}
Credit: Posting text/plain as a complex object in WebAPI with CORS
To Support additional function names other than just verbs (put/post/etc) (WebApiConfig.cs)"
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "APICustom",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
...
}
To support cors (web.config)
<httpProtocol>
<customHeaders>
<!-- cors -->
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
</customHeaders>
</httpProtocol>
API Controller, I called PersonController.cs
public class PersonController : ApiController
{
public List<string> Get()
{
List<string> s = new List<string>();
s.Add("s");
s.Add("t");
s.Add("u");
return s;
}
[Serializable()]
public class BaseReply
{
public bool successful = true;
public string error;
}
[Serializable()]
public class UpdateSomethingReply: BaseReply
{
public UpdateSomethingRequest request;
public List<string> stuff = new List<string>();
}
[Serializable()]
public class UpdateSomethingRequest
{
public int hasInt;
public string hasString;
}
//[FromBody]
[HttpPost]
public UpdateSomethingReply UpdateSomething([FromBody] UpdateSomethingRequest request)
{
string body = Request.Content.ReadAsStringAsync().Result;
UpdateSomethingReply reply = new UpdateSomethingReply();
reply.request = request;
reply.stuff.Add("v");
reply.stuff.Add("w");
reply.stuff.Add("x");
return reply;
}
That is the extent on the changes on the service. So next I create a client. This is also an mvc4 project. Pretty basic stuff here.
To polyfill ie8 with cors (index.cshtml):
<script src="~/Scripts/jQuery.XDomainRequest.js"></script>
Source: https://github.com/MoonScript/jQuery-ajaxTransport-XDomainRequest
To call the cors service
$(document).ready(function () {
$.when(
$.ajax({
url: urls.person.UpdateSomething,
type: 'post',
contentType: "application/json; charset=utf-8",
dataType: 'json',
data: JSON.stringify({
hasInt: 1,
hasString: "u"
})
})
)
.fail(function (jqXHR, textStatus, errorThrown) {
})
.done(function (data) {
console.log(JSON.stringify(data));
});
$.when(
$.ajax({
url: urls.person.Get,
dataType: 'json'
})
)
.fail(function (jqXHR, textStatus, errorThrown) {
})
.done(function (data) {
console.log(JSON.stringify(data));
});
$.when(
$.ajax({
url: urls.person.UpdateSomething,
type: 'post',
contentType: "text/plain",
dataType: 'json',
data: JSON.stringify({
hasInt: 1,
hasString: "u"
})
})
)
.fail(function (jqXHR, textStatus, errorThrown) {
})
.done(function (data) {
console.log(JSON.stringify(data));
});
});
As i stated earlier all 3 calls complete in ie8. But the request object in the service is null in ie8 and in firefox it is populated, even when i force the content-type to be text/plain
IE8 Console Output:
{"request":null,"stuff":["v","w","x"],"successful":true,"error":null}
Firefox Console Output:
{"request":{"hasInt":1,"hasString":"u"},"stuff":["v","w","x"],"successful":true,"error":null}
Update 9/25/2013
I can confirm that the body is being sent, but isn't being parsed by web api. If I add the following hack it will return the data as expected. In firefox the body will be empty and the request object is populated. In ie8 the body still contains the contents and the request is null.
[HttpPost]
public UpdateSomethingReply UpdateSomething(UpdateSomethingRequest request)
{
if (request == null && Request.Content.ReadAsStringAsync().Result !="")
{
request = JsonConvert.DeserializeObject<UpdateSomethingRequest>(Request.Content.ReadAsStringAsync().Result);
}
UpdateSomethingReply reply = new UpdateSomethingReply();
reply.request = request;
reply.body=Request.Content.ReadAsStringAsync().Result;
reply.headers = Request.Headers.ToString();
reply.stuff.Add("v");
reply.stuff.Add("w");
reply.stuff.Add("x");
return reply;
}