Cors, Web-API, IE8, Postkomplexe Daten

Als Teil meiner Arbeitsumgebung müssen wir IE8 unterstützen, möchten aber die Technologie vorantreiben, insbesondere CORS.

Ich habe Probleme, komplexe Objekte in ie8 an einen cors-Service zu senden. Das Objekt ist null. Nachfolgend sind die zu reproduzierenden Schritte aufgeführt. Bei Bedarf kann ich das Projekt auf github hochladen.

Ich habe ein neues MVC4-Projekt erstellt. API-Controller hinzugefügt. Und die folgenden Änderungen vorgenommen.

So unterstützen Sie komplexe cors-Preflight-Aufrufe (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(); }
    }

Quelle:Behandeln von CORS Preflight-Anforderungen an ASP.NET MVC-Aktionen

So unterstützen Sie text / plain (ie8 sendet nur text / plain mit 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); 

        ...
    }

Kredit:Posten von Text / Plain als komplexes Objekt in WebAPI mit CORS

Unterstützung zusätzlicher Funktionsnamen außer Verben (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 }
        );

        ...
    }
Cors unterstützen (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, ich habe PersonController.cs genannt
 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;
    }

Das ist der Umfang der Änderungen am Service. Als nächstes erstelle ich einen Kunden. Dies ist auch ein MVC4-Projekt. Ziemlich einfaches Zeug hier.

So füllen Sie ie8 mit cors (index.cshtml):
<script src="~/Scripts/jQuery.XDomainRequest.js"></script>

Quelle:https://github.com/MoonScript/jQuery-ajaxTransport-XDomainRequest

Den cors-Service anrufen
 $(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));
        });
    });

Wie ich bereits sagte, sind alle 3 Aufrufe in ie8 abgeschlossen. Aber das Anforderungsobjekt im Service ist in IE8 null und in Firefox wird es gefüllt, auch wenn ich den Inhaltstyp zwinge, Text / Plain zu sein

IE8-Konsolenausgabe:

{"request":null,"stuff":["v","w","x"],"successful":true,"error":null}

Firefox-Konsolenausgabe:

{"request":{"hasInt":1,"hasString":"u"},"stuff":["v","w","x"],"successful":true,"error":null}
Update 25.09.2013

Ich kann bestätigen, dass der Text gesendet wird, aber nicht von der Web-API analysiert wird. Wenn ich den folgenden Hack hinzufüge, werden die Daten wie erwartet zurückgegeben. In Firefox ist der Körper leer und das Anforderungsobjekt wird gefüllt. In ie8 enthält der Body noch den Inhalt und die Anfrage ist 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;
    }

Antworten auf die Frage(2)

Ihre Antwort auf die Frage