16

I am trying to get my application working by using REST, WCF and JSON (new to all those technologies). I have the 'GET' working fine. It is the 'POST' that is causing me problems.

As you will see below I 'pack up' my JSON using JSON.stringify, then fire off the POST to the REST resource. However, when the object gets to the WCF method that is handling the request the object is always null.

Here is the code:

$.ajax({
    type: "POST",
    dataType: "json",
    url: "Services/ContactCompanyService.svc/contactcompanies/customers",
    contentType: "application/json; charset=utf-8",
    data: JSON.stringify({ contactcompany: newCustomer }),
    success: function (html) { alert(html); }
});

Here is the config stuff:

<services>
  <service behaviorConfiguration="ServiceBehaviour" name="ContactCompanyService">
    <endpoint address="contactcompanies" behaviorConfiguration="web" binding="webHttpBinding" contract="IContactCompanyService"/>
  </service>

</services>

<behaviors>
  <endpointBehaviors>
    <behavior name="web">
      <webHttp/>
      <enableWebScript/>
    </behavior>
  </endpointBehaviors>
  <serviceBehaviors>
    <behavior name="ServiceBehaviour">
      <serviceMetadata httpGetEnabled="true"/>
      <serviceDebug includeExceptionDetailInFaults="false"/>
    </behavior>
    <behavior name="">
      <serviceMetadata httpGetEnabled="true"/>
      <serviceDebug includeExceptionDetailInFaults="false"/>
    </behavior>
  </serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true"/>

Here is the contract:

    [OperationContract]
    [WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped, UriTemplate = "customers")]
    [return: MessageParameter(Name = "ContactCompany")]
    ContactCompany AddContactCompany(ContactCompany ContactCompanyObject);

And it is the method that implements the above interface where ContactCompanyObject is null.

What on earth am I doing wrong? Please don't rule out stupidity on my part.

Further: I changed the WebMessageBodyStyle to .Bare, and this resulted in the object not being null ... but EVERY property of the object being null. That said, wrapped is the way I would like to go.

I would be grateful of any assistance. Let me know if you need further information.

UPDATE

I started from scratch with a completely new project - stripped back.

I am getting exactly the same result - the object, when received by the WCF code, is null.

Here's what I did on this new test project.

WCF Contract:

(under the namespace: NullTestService

[ServiceContract]
public interface IService1
{
    [OperationContract]
    [WebInvoke(Method = "GET", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped, UriTemplate = "NullTestPost")]
    [return: MessageParameter(Name = "NullTestType")]
    NullTestType GettMethod();

    [OperationContract]
    [WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped, UriTemplate = "NullTestPost")]
    [return: MessageParameter(Name = "NullTestType")]
    NullTestType PostMethod(NullTestType NullTestTypeObject);
}

[DataContract]
public class NullTestType
{
    [DataMember]
    public string NullTestString { get; set; }
    [DataMember]
    public int NullTestInt { get; set; }
}

Service Implementation: (same namespace)

    public class Service1 : IService1
{
    public NullTestType PostMethod(NullTestType NullTestTypeObject)
    {
        return NullTestTypeObject;
    }

    public NullTestType GettMethod()
    {
        return new NullTestType { NullTestString = "Returned String", NullTestInt = 25 };
    }

}

Website project. Service.svc:

<%@ ServiceHost Service="NullTestService.Service1" %>

web.config in the web project:

    <system.serviceModel>
<services>
  <service behaviorConfiguration="ServiceBehaviour" name="NullTestService.Service1">
    <endpoint address="nulltestaddress" behaviorConfiguration="web" binding="webHttpBinding" contract="NullTestService.IService1"/>
  </service>

</services>

<behaviors>
  <endpointBehaviors>
    <behavior name="web">
      <webHttp/>
    </behavior>
  </endpointBehaviors>
  <serviceBehaviors>
    <behavior name="ServiceBehaviour">
      <serviceMetadata httpGetEnabled="false" />
      <serviceDebug includeExceptionDetailInFaults="false"/>
    </behavior>
  </serviceBehaviors>
</behaviors>
</system.serviceModel>

and finally the jQuery in the web project:

$(function () {


//        $.ajax({
//            type: "GET",
//            url: "http://localhost:8080/TestWeb/Service.svc/nulltestaddress/nulltestpost",
//            success: alertResult
//        });

alert('about to do it');

$.ajax({
    type: "POST",
    url: "http://localhost:8080/TestWeb/Service.svc/nulltestaddress/nulltestpost",
    dataType: "json",
    contentType: "application/json; charset=utf-8",
    data: '{"NullTestType":{"NullTestString":"This is a post string","NullTestInt":25}}',
    success: alertResult
});

});

function alertResult(data) {
        alert(data.NullTestType.NullTestString);
}

So. The (commented out) GET works fine and returns the JSON. The POST does not. On the line:

public NullTestType PostMethod(NullTestType NullTestTypeObject)
{
    return NullTestTypeObject;
}

(the 'return' line) the NullTestTypeObject is always NULL.

I would be very grateful for help. I have lost a lot of time over this.

Vitaliy Ulantikov
  • 10,157
  • 3
  • 61
  • 54
GrayDS
  • 363
  • 1
  • 6
  • 18

1 Answers1

14

If Wrapped is what you want to do, then you need to wrap the request in the operation parameter name:

var input = { "ContactCompanyObject" : newCustomer };
$.ajax({
   data: input
   ...
});

Or for the second example, if you change the ajax call to the one shown below, you should get the expected result:

var input = { NullTestTypeObject: { NullTestString: "Hello", NullTestInt: 123} };
alert("Input: " + JSON.stringify(input));
$.ajax({
    type: "POST",
    url: "./Service1.svc/nulltestaddress/NullTestPost",
    contentType: "application/json",
    data: JSON.stringify(input),
    success: function (result) {
        alert("POST result: " + JSON.stringify(result));
    }
});
carlosfigueira
  • 85,035
  • 14
  • 131
  • 171
  • Thanks. I get what you are saying, but the JSON that is being created by the JSON.stringify looks correct to me. If you put a {blah:blahJavascriptObject} as the argument to stringify it does wrap the object with a 'blah' (so {"blah":{"Property1","Value"}}). – GrayDS May 18 '11 at 21:53
  • Yes, the stringify works. My input was actually wrong, you didn't need the operation name (I edited it to reflect it). The problem in your code is that the "wrapper" name (the outermost object member name) needs to match the operation parameter name. – carlosfigueira May 18 '11 at 22:40
  • Carlos .. I can't thank you enough. That was it; just using the wrong Wrapper -adding 'Object' to make it NullTestTypeObject) fixed it! Many thanks indeed. I know that you can override the wrapper value on the way out ([return: MessageParameter(Name = "NullTestType")] decoration on the method in the contract) but do you know of a way to change the incoming wrapper? Not urgent, but thought it would make a nice addition to this StackOverflow post if you knew. – GrayDS May 20 '11 at 10:40
  • Use the same [MessageParameter(Name = "wrapperName")], applied to the operation parameter itself. – carlosfigueira May 20 '11 at 13:06