Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is my Web API controller action not deserializing child properties of child properties?

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?

like image 631
sonicblis Avatar asked Aug 14 '14 17:08

sonicblis


2 Answers

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. =[

like image 177
sonicblis Avatar answered Nov 12 '22 07:11

sonicblis


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.

like image 36
Spidi's Web Avatar answered Nov 12 '22 07:11

Spidi's Web