2

I have a class that derives from a list, and no matter what I do, I cannot find where JSON.NET is setting the value. It appears to me that even properties marked are not firing.

I have set breakpoints at all the following areas:

public CartItem Add(int id, int numItems, CARTITEMTYPE type = CARTITEMTYPE.GENERIC)
    {
        var item = NewByType(type);
        item.ID = id;
        item.NumItems = numItems;
        return this.Add(item);
    }

    public new CartItem Add(CartItem item)
    {
        item.Parent = this;
        base.Add(item);
        return item;
    }

    public new void AddRange(IEnumerable<CartItem> items)
    {
        items.Any(f => { f.Parent = this; return true; });
        base.AddRange(items);
    }

    public new void InsertRange(int index, IEnumerable<CartItem> items)
    {
        items.Any(f => { f.Parent = this; return true; });
        base.InsertRange(index, items);
    }

    public new CartItem Insert(int index, CartItem item)
    {
        item.Parent = this;
        base.Insert(index,item);
        return item;
    }

But none of these have triggered a break when running deserialization.

The deserialization process is relatively straightforward, using this:

    public T GetJObject<T>(string cookieName, JsonSerializerSettings jset = null)
    {
        string cookieContent = Get(cookieName);
        return JsonConvert.DeserializeObject<T>(cookieContent, jset);
    }

And the converter class is also straightforward:

public class JsonCartConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(CartItem).IsAssignableFrom(objectType);
    }

    public override bool CanWrite
    {
        get
        {
            return false;
        }
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject obj = JObject.Load(reader);

        var type = obj["t"] != null ? (CARTITEMTYPE)obj["t"].Value<int>() : CARTITEMTYPE.GENERIC;
        var item = CartItems.NewByType(type);
        serializer.Populate(obj.CreateReader(), item);
        return item;
    }


    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {

    }
}

Even areas marked with JsonProperty in other classes are not being hit on deserialization.

[JsonProperty("c")]
    public CartItems Children
    {
        get
        {
            if (_Children == null) _Children = new CartItems();
            if (_Children.Parent == null) _Children.Parent = this;
            _Children.SiteID = SiteID;
            _Children.UserID = UserID;
            return _Children;
        }
        set
        {
            Children.Parent = this;
            Console.WriteLine("we set the parent");
            _Children = value;
        }
    }

So how does JSON.NET treat setters and lists? Obviously, neither are being hit? Can I force it to hit the setter logic?

EDIT: JSON

[{"t":1,"i":1,"n":4,"r":false,"c":[{"t":5,"i":2,"n":4,"r":false,"c":[]}]},{"t":1,"i":3,"n":4,"r":false,"c":[{"t":5,"i":4,"n":4,"r":false,"c":[{"t":4,"i":6,"n":14,"r":false,"c":[]}]},{"t":1,"i":5,"n":15,"r":false,"c":[]}]}]
dudeinco
  • 143
  • 1
  • 11
  • So is it hitting any of these? By inspecting the resulting class, it does not appear that the setter of the last example is ever getting hit? I am never seeing the parent get set... – dudeinco Mar 09 '17 at 21:40
  • Is it using reflection to bypass the setter logic, and standard add/insert functionality in classes completely, by forcing values into private properties? – dudeinco Mar 09 '17 at 21:42
  • JSON.NET will not invoke any 'add/insert' methods on your object. – hyankov Mar 09 '17 at 21:43
  • @HristoYankov That makes no sense. How would it even know which private field to insert it into? It *must* call the setter. I agree it uses reflection, yes, but it uses reflection to call the property setter. – dmeglio Mar 09 '17 at 21:49
  • @dman2306, I am sorry, you are correct. I have just tried it. The breakpoint in my setter IS hit, during debug. I will delete my comment to avoid further confusion. – hyankov Mar 09 '17 at 21:56
  • @dudeinco, if it's not hitting your breakpoint, then probably the JSON you are trying to deserialize does not match your object properties. Maybe you should post the JSON here. – hyankov Mar 09 '17 at 21:58
  • It is hitting the getter to set the children property instead of the setter. [JsonIgnore] needed to be set on the list class to prevent from being nulled out during deserialization... so that explains those two. I still have to intercept the setting of the parent derived List class to set the parent of its children though... Not sure how to do that. – dudeinco Mar 09 '17 at 23:21

1 Answers1

1

I have the answer for the way that it attaches the children in the CartItem class (last example in OP). It never calls the setter, because it is grabbing the class using the getter, then populating it from there. ...and of course, the parent of the child class must have the attribute [JsonIgnore] attached.

I'm still not sure how to intercept the populating of the class to set the parent of its children:

Public CartItems : List<CartItem>

on the deserialization to set the Parent property of the children, but this is one out of two answers.

Edit: The second issue was answered by dbc here:

Intercept list population to assign values in deserialization

Community
  • 1
  • 1
dudeinco
  • 143
  • 1
  • 11
  • 1
    Yes, that's correct, if the collection is pre-allocated it is never set back. See [Why are all the collections in my POCO are null when deserializing some valid json with the .NET Newtonsoft.Json component](https://stackoverflow.com/questions/32491966/why-are-all-the-collections-in-my-poco-are-null-when-deserializing-some-valid-js) for a related question. – dbc Mar 10 '17 at 19:00