it-swarm.com.de

Problem beim Senden von JSON-Daten von JQuery an WCF REST Methode

Ich habe Probleme, JQuery dazu zu bringen, einige Json-Daten zu einer Ruhe-Methode zu posten, die ich in meinem WCF-Dienst habe.

Auf der WCF-Seite hier der Betriebsvertrag:

[OperationContract]
[WebInvoke(Method = "POST",
           BodyStyle = WebMessageBodyStyle.Bare,
           RequestFormat = WebMessageFormat.Json,
           ResponseFormat = WebMessageFormat.Json,
           UriTemplate = "PostSomething")]
MyResult PostSomething(MyRequest request);

sowohl MyResult als auch MyRequest sind mit allen erforderlichen DataContract- und DataMember-Attributen markiert, und der Service stellt den WebHttp-Endpunkt bereit.

Auf der JQuery-Seite hier mein Funktionsaufruf:

var jsonStr = JSON.stringify(reqObj);

$.ajax({
    type: "POST",
    dataType: "json",
    url: "http://localhost/MyService/PostSomething",
    contentType: "application/json; charset=utf-8",
    data: jsonStr,
    success: function (html) {
        alert(html);
    }
});

diese Anfrage erreicht nie meine Methode (ich bekomme jedes Mal eine 405-Methode, die nicht zulässig ist), und in Charles sieht die Anfrage folgendermaßen aus:

OPTIONS /MyService/PostSomething HTTP/1.1
Host: localhost
Cache-Control: max-age=0
Access-Control-Request-Method: POST
Origin: null
Access-Control-Request-Headers: Content-Type, Accept
Accept: */*
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.237 Safari/534.10
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-GB,en-US;q=0.8,en;q=0.6
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

ein paar Dinge, die das seltsam sind:

  1. die Methode ist OPTIONS nicht POST
  2. der Inhaltstyp (in einem anderen Tab) zeigt text/html; charset=UTF-8 anstelle von json
  3. die JSON-Daten sind nicht sichtbar

Wenn ich jedoch die Anfrage in Charles so modifiziere, dass ihre Header der Lösung hier ähneln, funktioniert alles:

POST /MyService/PostSomething HTTP/1.1
Content-Type: application/json; charset=utf-8
Host: localhost
Content-Length: 152

{"Id":"", "Name":"testspot","Description":"test" } 

wenn Sie sich Tutorials und andere Fragen zu diesem Thema anschauen, haben andere es geschafft, JQuery dazu zu bringen, auf eine WCF REST -Methode wie diese zu posten, und ich bin ratlos darüber, was ich hier falsch mache.

oh, um etwas Kontext zu setzen, ist dies ein WCF 4-Dienst und ich verwende JQuery 1.4.4.

Vielen Dank,

UPDATE:

Nach einigem Lesen und Dank an Darrel, der mich auf die domänenübergreifenden Spezifikationen hinwies, gelang es mir, ein paar Schritte weiter zu gehen, indem ich einige kleine Änderungen an meinem Dienst an der Dienstschnittstelle vorgenommen habe:

[OperationContract]
[WebInvoke(Method = "*",
           BodyStyle = WebMessageBodyStyle.Bare,
           RequestFormat = WebMessageFormat.Json,
           ResponseFormat = WebMessageFormat.Json,
           UriTemplate = "PostSomething")]
MyResult PostSomething(MyRequest request);

in der Implementierung muss ich überprüfen, ob die eingehenden Anforderungen für OPTIONS gelten, und in diesem Fall einige Header zurückgeben, anstatt die beabsichtigte Arbeit auszuführen:

if (WebOperationContext.Current.IncomingRequest.Method == "OPTIONS")
{
    WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Origin", "*");
    WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Methods", "POST");
    WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Headers", "Content-Type, Accept");

    return null;
}

die Methode wird dann zweimal aufgerufen. Wenn der Server zum ersten Mal NULL zurückgibt, fügt er dem Client jedoch einige Header hinzu. Anschließend wird die eigentliche Anforderung mit POST als Methode erstellt, und der Server führt die Anfrage normal aus .

22
theburningmonk

Dies scheint eine Firefox-Sache zu sein, um domänenübergreifende Anrufe zu vermeiden. Siehe http://www.petefreitag.com/item/703.cfm

Die Spezifikation hierfür ist hier http://www.w3.org/TR/cors/ und nach sehr kurzer Lektüre scheint es so, als würde Ihr Dienst die Implementierung des OPTIONS-Methode und gibt einige Header zurück, die das Senden der Methode POST ermöglichen.

7
Darrel Miller

Das Update zu der Frage, die eine vorgeschlagene Lösung enthält, weist einige Probleme auf. Das Problem dabei ist, dass, wenn Ihre Eingabe die Methode POST nicht unterstützt, die Anforderung OPTIONS nicht die korrekten zulässigen Header zurückgibt. Es wird nicht wirklich untersucht, welche Methoden tatsächlich auf dem WCF-Endpunkt zulässig sind - es wird nur künstlich gesagt, dass "POST" für jeden einzelnen Endpunkt in der Anwendung zulässig ist, wenn ein Client eine OPTIONS-Anfrage ausführt (was wirklich der Client fragt, was unterstützt wird) ). 

Dies ist wahrscheinlich in Ordnung, wenn Sie sich nicht wirklich auf die Informationen in der OPTIONS-Methode verlassen, um eine gültige Liste von Methoden zurückzugeben (wie es bei einigen CORS-Anfragen der Fall ist). Wenn Sie dies tun, müssen Sie jedoch Folgendes tun die Lösung zu dieser Frage: Wie gehe ich mit Ajax JQUERY POST Anfrage mit WCF-Self-Host

Grundsätzlich sollte jeder Endpunkt Folgendes implementieren:

Webinvoke(Method="OPTIONS", UriTemplate="")

und eine geeignete Methode aufrufen, die die richtigen Header für die Antwort (einschließlich der richtigen Liste "Access-Control-Allow-Method" für diesen Endpunkt) für den Anrufer aufruft. Es ist schade, dass gehostete WCF-Endpunkte dies nicht automatisch für uns tun, aber dies ist eine Problemumgehung, die eine genauere Kontrolle über den Endpunkt ermöglicht. In dieser Lösung werden die richtigen Antwortheader an der Endpunktimplementierung geladen:

public void GetOptions()
    {
        // The data loaded in these headers should match whatever it is you support on the endpoint
        // for your application. 
        // For Origin: The "*" should really be a list of valid cross site domains for better security
        // For Methods: The list should be the list of support methods for the endpoint
        // For Allowed Headers: The list should be the supported header for your application

        WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Origin", "*");
        WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
        WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Headers", "Content-Type, Accept, Authorization");
    }

Darüber hinaus sollten Sie das Flag "CrossDomainScriptAccessEnabled" entweder in der web.config für den Bindungsendpunkt oder im Code für die WebHttpBinding festlegen, wenn Sie den Endpunkt konfigurieren. Andernfalls lügen Sie erneut in Ihrer Header-Antwort, wenn Sie sagen, dass "Access-Control-Allow-Origin" "*" (oder eine Liste von URLS) ist.

3
jeremyh

Aktualisieren:

Platzieren Sie .svc nach MyService, damit die URL gelesen wird

http://localhost/MyService.svc/PostSomething

Ich habe neulich selbst daran gearbeitet und bin auf Rick Strahls Blog gestoßen:

http://www.west-wind.com/weblog/posts/324917.aspx

Dies funktioniert einwandfrei für mich, also probieren Sie es aus!

Hoffentlich hilft das! :)

1
Yngve B-Nilsen

Haben Sie in Ihrer web.config webhttpbinding verwendet?

nur webhttpbinding unterstützt json.

0
Shiraz Bhaiji

Ich werde nur eine kurze Antwort posten, die mir geholfen hat, weil andere Antworten dies nicht getan haben.

  • Szenario: Ajax-Aufruf an den WCF-Dienst.
  • Fehlerursache: Automatische Anforderung von OPTIONS von ajax vor dem Senden der Anforderung POST . Die erste Anfrage konnte von meinem Dienst nicht bearbeitet werden.
  • Lösung: OPTIONS-Anfrage zulassen und darauf antworten.

Was musst du machen:

  1. Fügen Sie dies zu web.config hinzu:

    <system.webServer>
    <httpProtocol>
      <customHeaders>
        <add name="Access-Control-Allow-Origin" value="*" />
        <add name="Access-Control-Allow-Methods" value="GET,PUT,POST,DELETE,OPTIONS" />
        <add name="Access-Control-Allow-Headers" value="Content-Type" />
      </customHeaders>
    </httpProtocol>
    

  2. Fügen Sie dies zu Global.asax.cs hinzu (wenn diese Datei nicht in Ihrer Projektmappe enthalten ist, erstellen Sie sie wie folgt: Neues Element hinzufügen => Visual C # => Globale Anwendungsklasse (Standardname ist "Global.asax")):

    protected void Application_BeginRequest(object sender, EventArgs e)
    {
        if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
                        HttpContext.Current.Response.End();
    }
    
0
alexkovelsky