Jack Cantwell
Jack Cantwell

Reputation: 41

JSON object has null array properties on WCF REST POST

I'm POSTing a JSON object to a REST API in WCF. The string and int properties come through just fine, but the properties of type IList are null, even though they're specified in the JSON.

Here's what the JSON object looks like after it's been stringified:

{
    "Id":"1",
    "Name":"Group One ertqer",
    "Description":"This is group 1 estrfasd",
    "SecurityPrincipals":"[
        {
            "Id": "1",
            "DisplayName": "User One",
            "UserName": "user.one",
            "Sid": "null",
            "Fqdn": "gmd.lab" 
         } ,
        {
            "Id": "2",
            "DisplayName": "User Two",
            "UserName": "user.two",
            "Sid": "null",
            "Fqdn": "gmd.lab" 
         }
     ]",
    "SecurityPermissions":"[
        {
            "Id": "2",
            "Name": "Access Service Catalog"
        } ,
        {
            "Id": "1",
            "Name": "Access Portal"
        }
    ]"
}

Here's the jQuery AJAX code I'm using to POST the object:

var securitygroup = {
    group: {
        Id: $("#csm-security-groupid").val(),
        Name: $("#csm-security-groupname").val(),
        Description: $('#csm-security-groupdesc').val(),
        "SecurityPrincipals[]": principals,
        "SecurityPermissions[]": permissions
    }
};

$.ajax({
    url: 'http://localhost:809/RestDataServices/RestDataService.svc/SecurityGroups/SecurityGroup',
    contentType: "application/json; charset=utf-8",
    data: JSON.stringify(securitygroup),
    dataType: 'json',
    type: 'POST',
    async: true,
    success: function (data, success, xhr) {
        alert('Group saved - ' + success);
    },
    error: function (xhr, status, error) {
        alert('Error! - ' + xhr.status + ' ' + error);
    }
});

and here is the REST operation contract:

[OperationContract]
[WebInvoke(Method = "POST",
    RequestFormat = WebMessageFormat.Json,
    BodyStyle = WebMessageBodyStyle.Bare,
    UriTemplate = "SecurityGroups/SecurityGroup")]
void SaveSecurityGroup(SecurityGroup group);

The data contract of SecurityGroup:

[DataContract]
public class SecurityGroup
{
    [DataMember]
    public int Id { get; set; }

    [DataMember]
    public string Name { get; set; }

    [DataMember]
    public string Description { get; set; }

    [DataMember]
    public IList<SecurityPermission> SecurityPermissions { get; set; }

    [DataMember]
    public IList<SecurityPrincipal> SecurityPrincipals { get; set; }

}

and finally, here's the relevant part of the REST service's web.config:

  <system.serviceModel>
    <services>
      <service name="RestDataServices.RestDataService" behaviorConfiguration="DefaultBehavior">
        <endpoint address="" binding="webHttpBinding" contract="RestDataServices.IRestDataService" behaviorConfiguration="web"/>
      </service>
    </services>
    <behaviors>
      <endpointBehaviors>
        <behavior name="web">
          <webHttp/>
        </behavior>
      </endpointBehaviors>
      <serviceBehaviors>
        <behavior name="DefaultBehavior">
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
    <directoryBrowse enabled="true"/>
    <httpProtocol>
     <customHeaders>
       <add name="Access-Control-Allow-Origin" value="*" />
     </customHeaders>
   </httpProtocol>
  </system.webServer>

So I've tried a bunch of different things:

1) tried both wrapped and unwrapped 2) originally the data contract had List<> properties, rather than IList<>, but obviously that didn't work 3) I've poked through about a dozen other questions here on StackExchange and none of them seem to be relevant to my problem.

I'd rather not have to create a custom formatter...I'm guessing that I'm just doing something wrong that will turn out to be very simple.

Any help on this would be very appreciated. I've already spent about 6 hours on this and I'm about to give up and post the arrays themselves as separate calls.

Upvotes: 0

Views: 1561

Answers (2)

Jack Cantwell
Jack Cantwell

Reputation: 41

OK, the answer was that I needed to do 2 things differently.

1) I had added quotation marks and square brackets to my JSON array assignments because I was getting a 400 - Bad Request without them. This was the source of my null array/list properties.

var securitygroup = {
    group: {
        Id: $("#csm-security-groupid").val(),
        Name: $("#csm-security-groupname").val(),
        Description: $('#csm-security-groupdesc').val(),
        "SecurityPrincipals[]": principals, //bad
        "SecurityPermissions[]": permissions //bad
    }
};

2) once I removed the "" and [] on the SecurityPrincipals and SecurityPermissions properties, I got the 400 - Bad Request again. I noticed that my integer properties had quotes around them, so I forced them to be integers using parseInt. I'm also forcing "null" to a proper null value. Here's what the JSON-building code looks like, now:

var principals = [];
$("li[data-type='permission']").each(function () {
    principals.push(
        {
            Id: parseInt(this.id),
            DisplayName: this.getAttribute('data-name'),
            UserName: this.getAttribute('data-username'),
            Sid: this.getAttribute('data-sid') == "null" ? null : this.getAttribute('data-sid'),
            Fqdn: this.getAttribute('data-fqdn')
        }
    );
});

//permissions for the current group
var permissions = [];
$("input[type='checkbox']").each(function () {
    if (this.getAttribute("checked") == "checked") {
        permissions.push(
            {
                Id: parseInt(this.getAttribute('data-id')),
                Name: this.getAttribute('data-name')
            }
        );
    }
});

var securitygroup = {
    group: {
        Id: parseInt($("#csm-security-groupid").val()),
        Name: $("#csm-security-groupname").val(),
        Description: $('#csm-security-groupdesc').val(),
        SecurityPrincipals: principals,
        SecurityPermissions: permissions
    }
};

Upvotes: 1

user749105
user749105

Reputation: 191

Remove the quotation marks before the [, and after the ].

There are no lists (or iLists?) in JSON.

The [] indicate an array.

Refer to http://www.json.org/

Upvotes: 0

Related Questions