Mark Richman
Mark Richman

Reputation: 29710

WCF not deserializing JSON input

I have a WCF service defined as follows:

Imports System.ServiceModel
Imports System.ServiceModel.Web

<ServiceContract()>
Public Interface ILayoutService

  <OperationContract()>
  <WebInvoke(Method:="POST",
             BodyStyle:=WebMessageBodyStyle.WrappedRequest,
             RequestFormat:=WebMessageFormat.Json,
             ResponseFormat:=WebMessageFormat.Json)>
  Sub SaveLayout(ByVal layout As Layout)

  <OperationContract()>
  Function GetLayout() As Layout

End Interface

The Layout class is defined as:

Imports System.Runtime.Serialization

<DataContract()>
Public Class Layout

  <DataMember()>
  Public Property Columns As New List(Of ContentColumn)

End Class

<DataContract()>
Public Class ContentColumn
  <DataMember()>
  Public Property Name As String = "Column Name"

  <DataMember()>
  Public Property Position As Integer

  <DataMember()>
  Public Property Modules As New List(Of ContentModule)

End Class

<DataContract()>
Public Class ContentModule

  <DataMember()>
  Public Property Name As String = "Module Name"

  <DataMember()>
  Public Property Position As Integer

End Class

The implementation of ILayoutService is as follows:

Imports System.ServiceModel.Activation
Imports System.Web.Script.Serialization

<AspNetCompatibilityRequirements(RequirementsMode:=AspNetCompatibilityRequirementsMode.Required)>
Public Class LayoutService
  Implements ILayoutService

  Public Sub SaveLayout(ByVal layout As Layout) Implements ILayoutService.SaveLayout
    Dim l As New Layout
    Dim left, center, right As New ContentColumn

    left.Name = "Left Column"
    left.Position = 0
    center.Name = "Center Column"
    center.Position = 1
    right.Name = "Right Column"
    right.Position = 2

    Dim topLeft, centerLeft, bottomLeft, topCenter, centerCenter, bottomCenter, topRight, centerRight, bottomRight As New ContentModule

    topLeft.Name = "Top Left"
    topLeft.Position = 0
    centerLeft.Name = "Center Left"
    centerLeft.Position = 1
    bottomLeft.Name = "Bottom Left"
    bottomLeft.Position = 2

    topCenter.Name = "Top Center"
    topLeft.Position = 0
    centerCenter.Name = "Center Center"
    centerCenter.Position = 1
    bottomCenter.Name = "Bottom Center"
    bottomCenter.Position = 2

    topRight.Name = "Top Right"
    topRight.Position = 0
    centerRight.Name = "Center Right"
    centerRight.Position = 1
    bottomRight.Name = "Bottom Right"
    bottomRight.Position = 2

    left.Modules.Add(topLeft)
    left.Modules.Add(centerLeft)
    left.Modules.Add(bottomLeft)

    center.Modules.Add(topCenter)
    center.Modules.Add(centerCenter)
    center.Modules.Add(bottomCenter)

    right.Modules.Add(topRight)
    right.Modules.Add(centerRight)
    right.Modules.Add(bottomRight)

    l.Columns.Add(left)
    l.Columns.Add(center)
    l.Columns.Add(right)

    Dim json As New JsonResult
    json.Data = l
    Dim serializer As New JavaScriptSerializer
    Dim output = serializer.Serialize(json.Data)
  End Sub

  Public Function GetLayout() As Layout Implements ILayoutService.GetLayout
    Dim l As New Layout
    Dim c As New ContentColumn
    Dim m As New ContentModule
    c.Modules.Add(m)
    l.Columns.Add(c)
    Return l
  End Function
End Class

I implemented SaveLayout() so I can get the literal JSON that would be (de)serialized. I'm using that to test invoking this service via jQuery:

$(document).ready(function () {

  $("#saveLayout").click(function () {

    var layout = buildLayout();
    var jsonLayout = $.toJSON(layout);

    $.ajax({
      type: "POST",
      contentType: "application/json; charset=utf-8",
      dataType: "json",
      url: "/Services/LayoutService.svc/SaveLayout",
      data: jsonLayout,
      dataType: "json",
      success: function (result) {
        alert(result.d.Columns[0].Name);
      },
      error: function (xhr, ajaxOptions, thrownError) {
        var jsonFault = JSON.parse(xhr.responseText);
        alert(jsonFault.Message);
      }
    });
    return false;
  });

});

function buildLayout() {
  var layout = { "Columns": [
    { "Name": "Left Column", "Position": 0, "Modules": [
      { "Name": "Top Left", "Position": 0 },
      { "Name": "Center Left", "Position": 1 },
      { "Name": "Bottom Left", "Position": 2}]
    },
    { "Name": "Center Column", "Position": 1, "Modules": [
      { "Name": "Top Center", "Position": 0 },
      { "Name": "Center Center", "Position": 1 },
      { "Name": "Bottom Center", "Position": 2}]
    },
    { "Name": "Right Column", "Position": 2, "Modules": [
      { "Name": "Top Right", "Position": 0 },
      { "Name": "Center Right", "Position": 1 },
      { "Name": "Bottom Right", "Position": 2}]
    }]
  };

  return layout;
}

The layout returned by buildLayout() is the exact JSON returned by the serialize() call in the VB code. For some reason, when I invoke the web service, the input parameter layout in SaveLayout() is Nothing. Something must be failing on deserialization. Any idea why?

Upvotes: 1

Views: 1748

Answers (1)

krisragh MSFT
krisragh MSFT

Reputation: 1918

it's hard to tell from just the detail you've provided.

Here is what I suggest:

Generally, once you do this, you should plenty of more info on what's going funky at the service side and can diagnose the issue pretty quickly. Try it, and please report back! :)

Upvotes: 1

Related Questions