user123456
user123456

Reputation: 133

Error cross domain call using WCF Rest

I'm trying to make a WCF service with CORS calls, so far, I have my server with the classes indicated here: http://enable-cors.org/server_wcf.html

I was able to make a call with a jQuery ajax call using the verb GET without any parameters, the problem comes when I try to pass parameters to my request, here's my code:

Interface markup:

[OperationContract]
[WebInvoke(Method = "*",
           RequestFormat = WebMessageFormat.Json,
           ResponseFormat = WebMessageFormat.Json,
           BodyStyle = WebMessageBodyStyle.WrappedRequest)]
string GetData(TestClass value);

Method markup:

public string GetData(TestClass value)
{
     return value.Id.ToString();
}

js markup:

var value = { 
    Id : "2", 
    Name: "qwe" 
};

$.ajax({
    url: "http://localhost:38733/Service1.svc/GetData",
    type: "POST",
    contentType: "application/json",
    dataType: "json",
    data: JSON.stringify({ value: value }),
    success: function(result) {
        console.log(result);
    },
    error: function(jqXHR, textStatus, errorThrown) {
        console.log(jqXHR);
    }
});

But if I debug, I always get null, meaning that the parameter is not being passes to the method, I also got POST http://localhost:38733/Service1.svc/GetData 400 (Bad Request) on Chrome console.

What am I doing wrong?

UPDATE

Web.config markup:

<behavior name="jsonBehavior">
    <webHttp />
    <crossOriginResourceSharingBehavior />
</behavior>

<extensions>
  <behaviorExtensions>
    <add name="crossOriginResourceSharingBehavior" 
         type="WCFSecureService.EnableCrossOriginResourceSharingBehavior, WCFSecureService, Version=1.0.0.0, Culture=neutral" />
  </behaviorExtensions>
</extensions>

<services>
  <service name="WCFSecureService.Service1">
    <endpoint address="" 
              binding="webHttpBinding" 
              behaviorConfiguration="jsonBehavior" 
              contract="WCFSecureService.IService1" />
  </service>
</services>

On the Google Chrome Console I'm getting the following:

OPTIONS http://localhost:38733/Service1.svc/GetData?value=5

UPDATE

It works if I make a request to a method without any parameters

UPDATE

Fiddler 2 is showing me this, so I don't know what I'm doing wrong...

request error

UPDATE

TestClass markup:

[DataContract]
public class TestClass
{
    private int id;
    private string name;

    [DataMember]
    public string Name
    {
        get { return name; }
        set { name = value; }
    }

    [DataMember]
    public int Id
    {
        get { return id; }
        set { id = value; }
    }        
}

UPDATE

If I use JSON.stringify({ value: value }) and BodyStyle = WebMessageBodyStyle.Bare I reach the server, but I got all properties with 0, check the next image:

error on debug

Upvotes: 2

Views: 239

Answers (2)

user123456
user123456

Reputation: 133

I've found a solution for my case. At the end this was a test, so I'm gonna be using more that just one parameter so this is what I've learn:

  • For more than one parameter, the request has to be wrapped, so, the annotation of the contract for WebInvoke has to be BodyStyle = WebMessageBodyStyle.WrappedRequest.
  • On the client side, for just one parameter, using JSON.stringify(value) it's ok, but for more than one, you have to be more specific, for example:

    data: JSON.stringify({
        value: value, 
        text: "any text"
    });
    
  • On the link I provide on my question, I have to included two clases CustomHeaderMessageInspector and EnableCrossOriginResourceSharingBehavior, it seems that they are not longer needed if you can make use of a global.asax file, you just have to add the following code to Application_BeginRequest:

    HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
    if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
    {
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "POST, PUT, DELETE, GET");
    
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
        HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
        HttpContext.Current.Response.End();
    }
    

And my web.config end it up like this:

<bindings>
  <webHttpBinding>
    <binding name="Binding" crossDomainScriptAccessEnabled="true">
      <security mode="Transport">
        <transport clientCredentialType="None" />
      </security>
    </binding>
    <binding name="corsBinding" crossDomainScriptAccessEnabled="true" />
  </webHttpBinding>
</bindings>

<services>
  <service name="WCFSecureService.Service1" behaviorConfiguration="ServiceBehaviour">
    <endpoint address="bs" binding="basicHttpBinding" contract="WCFSecureService.IService1" />
    <endpoint address="" 
              binding="webHttpBinding"
              bindingConfiguration="corsBinding"
              behaviorConfiguration="jsonBehavior"
              contract="WCFSecureService.IService1" />
  </service>
</services>

<behaviors>
  <serviceBehaviors>
    <behavior name="ServiceBehaviour">
      <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
      <serviceDebug includeExceptionDetailInFaults="true" />
    </behavior>
    <behavior name="jsonBehavior">
      <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
      <serviceDebug includeExceptionDetailInFaults="true" />
    </behavior>
  </serviceBehaviors>

  <endpointBehaviors>        
    <behavior name="jsonBehavior">
      <webHttp helpEnabled="true" />
    </behavior>
  </endpointBehaviors>
</behaviors>

Thanks for your helps and I hope it helps someone else out there.

Upvotes: 1

Ross Bush
Ross Bush

Reputation: 15185

In your service contract you might want to put an optional WebGet directive.

[WebGet(UriTemplate = "GetData/{value}")]
string GetData(int value);

Another thing to look for is that you have a json behavior defined for your enpoint in the web.config.

<endpointBehaviors>
    <behavior name="jsonBehavior">
        <webHttp defaultOutgoingResponseFormat="Json"/>
    </behavior>
    <behavior name="xmlBehavior">
      <webHttp defaultOutgoingResponseFormat="Xml"/>
    </behavior>
</endpointBehaviors>

NOTE: If you are using behaviors and then you need to specify the format in the following manner

http://localhost:38733/Service1.svc/json/GetData/5

or

http://localhost:38733/Service1.svc/xml/GetData/5

Also, could you try this js instead:

var _data= {
    value:5
};

$.ajax({
    ...
    data: _data,
    success: function(data) {
        console.log(data);
    },
    error: function(jqXHR, textStatus, errorThrown) {
        console.log(jqXHR);
    }
});

Or conversely:

$.ajax({
    url: "http://localhost:38733/Service1.svc/json/GetData/5",
});

Upvotes: 1

Related Questions