0

I am trying to deserialize following JSON (simplified) to pointout the issue. The SampleRuleSet loses the Parent using $ref information whereas it exist in the JSON, and interesting for all the Children underneath SampleRuleSet have the Parent information available after deserialization.

It's a very strange behavior i have encountered and my researching didn't lead me to any concrete solution. I do however think its happening due to the ordering of the elements for which i used OrderedContractResolver class from the following post but issue is still there.

{
  "$id": "119",
  "$type": "FSX.Client.Entities.RuleFolder, FSX.Client.Entities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",
  "Children": [
    {
      "$id": "120",
      "$type": "FSX.Client.Entities.RuleSet, FSX.Client.Entities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",
      "Children": [
        {
          "$id": "121",
          "$type": "FSX.Client.Entities.SetValue, FSX.Client.Entities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",
          "Id": "d835028e-f630-42fa-b77d-af1b8abbc7a3",
          "Name": "iterator",
          "Parent": {
            "$ref": "120"
          }
        },        
        {
          "$id": "138",
          "$type": "FSX.Client.Entities.SetValue, FSX.Client.Entities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",
          "Id": "0101075c-c9dc-4f9d-9681-c72cc278e69f",
          "Name": "Set_pvFv",
          "Parent": {
            "$ref": "120"
          }
        }        
      ],
      "Id": "b87ee6b6-a461-4669-bfce-31d5ed821458",
      "Name": "SampleRuleSet",
      "Parent": {
        "$ref": "119"
      }
    }
  ],
  "Id": "5d950d31-1eec-4beb-ab11-21c20b183f81",
  "Name": "Financial",
  "Parent": null
}

Following is my Services API settings:

services.AddControllersWithViews()
    .AddNewtonsoftJson(options =>
        {
            options.SerializerSettings.ContractResolver = new OrderedContractResolver();
            options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Serialize;
            options.SerializerSettings.PreserveReferencesHandling = PreserveReferencesHandling.Objects;
            options.SerializerSettings.TypeNameHandling = TypeNameHandling.Objects;
            options.SerializerSettings.TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Full;
        }
    );

And i have similar settings at the consuming end.

Classes:

[DataContract]
public abstract class GenericRule : ClientEntity
{
    protected GenericRule() : this(null) { }

    protected GenericRule(string name)
    {
        Name = name;
    }

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

    [DataMember]
    public ContainerRule Parent { get; set; }
}

[DataContract]
public abstract class ContainerRule : GenericRule
{
    [DataMember(Name = nameof(Children))]
    protected ObservableCollection<GenericRule> _children =
        new ObservableCollection<GenericRule>();
    public IEnumerable<GenericRule> Children => _children.AsEnumerable();
}

[DataContract]
public abstract class ActionRule : GenericRule { }

[DataContract]
public class Entity : ClientEntity { }

[DataContract]
public class RuleFolder : ContainerRule 
{ 
    private RuleFolder() { }
    public RuleFolder(Entity entity) { } // the only way to construct this object is by using this ctor
}

[DataContract]
public class RuleSet : ContainerRule { }

[DataContract]
public class SetValue : ActionRule { }

One important bit, i have not decorated any of my class properties with [JsonProperty], they are just decorated with [DataMember], and my intend is also not to decorate so i am looking for solution without attribute decoration.

Furqan Safdar
  • 16,260
  • 13
  • 59
  • 93
  • We need to see your classes to help you, can you share a [mcve]? e.g. if the parent is set by passing it into the child's constructor then that won't work, see [Usage of non-default constructor breaks order of deserialization in Json.net](https://stackoverflow.com/q/36866131/3744182). – dbc Apr 08 '20 at 15:16
  • I have added the relevent classes, just to answer your question, nothing is passed in constructor for Parent setting, i know how it impacts the serialization process. – Furqan Safdar Apr 08 '20 at 16:11
  • You have `[DataMember]` applied to properties, but `[DataContract]` is not applied to any of the types. Absent `[DataContract]`, `[DataMember]` does nothing. – dbc Apr 08 '20 at 16:53
  • As i told in my question, i am trying to simply things, [DataContract] is in place, obviously serialization is taking place as i mentioned but only SampleRuleSet `Parent` is not getting populated after deserialization. However, i have updated the classes again adding `[DataContract]` :) – Furqan Safdar Apr 08 '20 at 16:56
  • Can't reproduce trying to round-trip a simple test case or with the JSON and classes provided (fixed to allow for compilation, and successful type resolution): https://dotnetfiddle.net/4QrJxI – dbc Apr 08 '20 at 17:25
  • Thanks for your effort, i am now going to add your testing code to my actual source code and try to reproduce the issue, it might break but let me give it a try this way. – Furqan Safdar Apr 08 '20 at 18:16
  • @dbc, i have figured out the issue by revisting my entities closely, your testing code helped me in this regard. I have forked and updated your code here https://dotnetfiddle.net/DVmGoc which signifies the probem, where the private constructor in RuleFolder class was causing this trouble. I have updated my question adding the constructor. Thanks for your help, If you answer the question, i will accept it as a gratitude for being helpful. – Furqan Safdar Apr 09 '20 at 09:50

0 Answers0