7

I'm sending a json payload in a PUT request to a web API controller action. The action in question has a signature that looks like this:

public IHttpActionResult Post([FromBody]SaveThingRequest request)

SaveThingRequest looks something like this:

public class SaveThingRequest
{
    public List<ElementInfo> Elements { get; set; }

    public class ElementInfo
    {
        public List<ElementSettingInfo> Settings { get; set; }

        public class ElementSettingInfo
        {
            public string Name { get; set; }
            public string Value { get; set; }
        }
    }
}

I'm posting json in the body of the request that contains Elements that have Settings. I've confirmed this by manually deserializing in the controller action and confirming that the JSON has a structure that looks something like:

{
    Elements: [
        {
            Settings: [
                {
                    Name: 'Name 1',
                    Value: 'Value 1'
                },
                {
                    Name: 'Name 2',
                    Value: 'Value 2'
                }
            ]
        },
        {
            Settings: [
                {
                    Name: 'Name 1',
                    Value: 'Value 1'
                },
                {
                    Name: 'Name 2',
                    Value: 'Value 2'
                }
            ]
        }
    ]
}

However, when .NET deserializes the payload and creates the SaveThingRequest, my Elements are populated but all of them have a null Settings property. I don't know how else to troubleshoot this. Does anyone have any thoughts on what might be going on here?

sonicblis
  • 2,926
  • 7
  • 30
  • 48
  • Paste your payload in the question. Nm, I'm blind. – Langdon Aug 14 '14 at 17:20
  • I was stuck in the same problem. However, the problem was something else. In my case, the property that was not getting serialized didn't had a default constructor. – Daniel Iancu Jan 23 '17 at 10:13

5 Answers5

23

This question should be deleted. It works as advertised. My problem was that I had an additional property on the JSON called 'settings' (lower-case) that the deserializer was trying to match because NewtonSoft deserialization attempts a non-case sensitive match if a case sensitive one isn't found. I was able to discover what was happening by changing the signiture of the method to:

public IHttpActionResult Post([FromBody]string request)

and then adding this to the method implementation:

var result = JsonConvert.DeserializeObject<SaveThingRequest>(request);

I got a deserialization exception saying:

Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[Noteable.Contracts.ClinicalReports.SaveThingRequest+ElementInfo+ElementSettingInfo]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly. To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object. Path 'Elements[0].settings.TextSize', line 11, position 20.

The end of the message showed me what was being deserialized when the deserializer failed and pointed me in the right direction. =[

keeehlan
  • 7,874
  • 16
  • 56
  • 104
sonicblis
  • 2,926
  • 7
  • 30
  • 48
  • 1
    I had a similar scenario where complex object types were not being deserialized appropriately on the webapi request deserializer. I used this solution to debug the issue and correct the serialization process. Yes WebAPI was doing exactly what it should, but it also didnt provide me with a reason or way to address the change specifically that I needed. thanks – Itanex Mar 04 '15 at 19:37
  • 2
    this is a very helpful way to get to the real source of the problem. any idea how to capture the real underlying JSON exception when it occurs? – Simon_Weaver Oct 27 '15 at 09:15
  • 4
    This is a very good solution to help you debug your deserializing issues with your web apis. – Elferone Feb 19 '16 at 13:19
  • 6
    The real stackoverflow is when you answer your own question and provide everyone with a valuable debugging method. – Andy Arndt Mar 29 '17 at 15:25
  • 3
    This helped me immensely. Thanks for this troubleshooting method. – Zach Jun 20 '19 at 21:00
  • This doesn't make sense to me. `object.ToString()` returns `System.Object`. How is this useful when debugging deserialization issues? – keeehlan Aug 18 '22 at 20:54
  • @keeehlan The helpful part is in using the `JsonConvert.DeserializeObject` call to manually deserialize. When Web.API does deserialization of action parameters, it makes a lot of assumptions and covers a multitude of sins when doing so and you don't get to see as much of what's going on. Doing it manually with `DeserializeObject` is much more strict and will give you insight to issues that Web.API deserialization might hide. – sonicblis Aug 30 '22 at 16:25
5

I was stuck in the same problem. However, the problem was something else.

In my case, the property that was not getting serialize was declared without public access specifier. I declared it to public, and it ran perfectly fine.

Hope this will help someone who got stuck in this situation. It took me 20 mins to reach this solution.

Aman Jain
  • 655
  • 5
  • 17
0

Make sure you didn't do something stupid like I did and sent a partially 'stringified' JSON string from the browser instead of a JSON object.

See the problem? I didn't at first until I tried deserializing it from a string and then I realized that shippingAddress itself was a string instead of being an actual JSON object. The rest of the object was proper JSON, but I accidentally serialized the shippingAddress field.

{ "fspID": 571285, "foo": 444, "shippingAddress": "{\"countryCode\":\"US\",\"firstName\":\"Test User\",\"lastName\":null,\"address1\":\"1 Main St4\",\"address2\":null,\"company\":null,\"city\":\"San Jose\",\"stateOrProvince\":\"California\",\"stateCd\":\"CA\",\"zipOrPostal\":\"95131\",\"countryName\":\"United States\",\"countryDesc\":\"United States\",\"phone\":null,\"phone2\":null}" }

Simon_Weaver
  • 140,023
  • 84
  • 646
  • 689
0

If you are using JSON.NET and the attribute [JsonProperty] to name a property – make sure you haven't accidentally copy pasted the same property twice and forgotten to update the string value.

 [JsonProperty("billingAddress")]
 public Address BillingAddress { get;set; }

 [JsonProperty("billingAddress")]
 public Address ShippingAddress { get;set; }

This will throw a Newtonsoft.Json.JsonSerializationException that won't actually be visible to you and will screw up the model.

Simon_Weaver
  • 140,023
  • 84
  • 646
  • 689
0

I had the same problem that the child property was null. However the problem was something else.

I had only a getter on the property, once I added a setter as well, then the property was set as expected.

Tim Pickin
  • 369
  • 4
  • 15