简体   繁体   中英

JSON.NET Serialize Nested Complex Dictionary object

I have a multiple level class (vpc/subnet/instance). They are 1 to many relationship.

  • one vpc could have multiple subnet.
  • one subnet could have multiple instance

Every object is a standalone class and I am using a dictionary hold child objects. So the dictionary is Dictionary <string, child object> .

The child object could be different types but they all from same base class. I am using generics in the class.

Here is the code for the vpc class:

public class CEVpcBase : CECloudVpcBase
{
    [JsonProperty("CESubnetCache")]
    public CESubnetCache CESubnetCache { get; set; }
    public CESnapshotCache CESnapshotCache { get; set; }
    public List<CEVpcGroup> CEVpcGroups { get; set; }
    public BrokerAuthenticationBase BrokerAuthentication;
    protected DynamoDBHelper dynamoDbHelper;

    public CEVpcBase(DynamoDBHelper dynamoDbHelper)
    {
        this.dynamoDbHelper = dynamoDbHelper;
        //we can's init subnet/snapshot cache here because, we need the cloud account
        //the cloud account is not init until the base class init
        this.CEVpcGroups = new List<CEVpcGroup>();
    }
...
}

Here is the code for the child object:

public class CESubnetCache : CECacheBase<CESubnetBase>
{
    [JsonIgnore]
    public CEVpcBase ParentVpc { get; }
    [JsonConstructor]
    public CESubnetCache()
    {

    }
    public CESubnetCache(CEVpcBase vpc, DynamoDBHelper dbHelper) : base(dbHelper)
    {
        this.ParentVpc = vpc;
        this.ec2Client = CloudClientFactory.GetCloudClient(ParentVpc.CloudAccount, CloudClientType.AwsEC2) as AmazonEC2Client;
        this.CreatedOn = DateTime.Now;
        log.InfoFormat("ParentVpc:{0}**{1} subnet cache created", ParentVpc.ObjectId, ParentVpc.ObjectName);
    }
}

The dictionary is in the base class.

[JsonObject(MemberSerialization.OptIn)]
public abstract class CECacheBase<T>
{
    [JsonIgnore]
    protected AmazonEC2Client ec2Client;
    [JsonIgnore]
    protected log4net.ILog log = log4net.LogManager.GetLogger(typeof(CECacheBase<T>));
    protected ConcurrentDictionary<string, T> items = new ConcurrentDictionary<string, T>();
    protected DateTime CreatedOn;
    protected DateTime UpdatedOn;
    public string test = "test";
    public virtual async Task Load() { }
    public virtual async Task Load(object o) { }
    public virtual async Task<ConcurrentDictionary<string, T>> Load(string id, string name) { return null; }
    protected bool isInitialized = false;
    protected object lockObject = new object();
    [JsonIgnore]
    protected DynamoDBHelper dynamoDBhandler;
    [JsonConstructor]
    public CECacheBase()
    {

    }
}

And here is the code for CESubnetBase:

public class CESubnetBase : CECloudSubnetBase
{
    [JsonIgnore]
    public CEVpcBase ParentVpc { get; set; }
    [JsonProperty("CEInstanceCache")]
    public CEInstanceCache CEInstanceCache { get; set; }
    [JsonConstructor]
    public CESubnetBase()
    {

    }
}

I have tried all different kinds of json.net attributes. But in the serialized json file the CESubnetCache shows as an empty object {} . In my code, shown above, the CESubnetCache class has an items dictionary. I expected that the dictionary would be serialized.

"vpc-68c3090c": {
"BrokerAuthentication": null,
"CESubnetCache": {},
"CESnapshotCache": {},
"CEVpcGroups": [],
"VpcCidr": "10.1.0.0/16",
"InstanceStatic": null,
"StackId": "arn:aws-cn:cloudformation:cn-north-1:663242140710:stack/MYCloud-2017-3-18-10-28-6/93f37bc0-0bc5-11e7-8d6d-50fa18a0d262",
"StackName": "MYCloud-2017-3-18-10-28-6",
"AdNatStatus": null,
"StackStatus": null,
"VpcSummary": {
  "LanSgId": null,
  "DmzSgId": null,
  "GatewayIP": "54.223.239.78",
  "ADInstanceId": "i-0be9a18f05927dea2",
  "VpcType": null,
  "AuthenticationType": "AD",
  "DomainName": "MYCloud.local",
  "IsSoftDeleted": false
},
"VpcMetadata": {
  "CloudAccountId": "AWS-663242140710-CNNorth1",
  "VpcDns": "MYCloud",
  "AdAmiId": null,
  "NatAmiId": null
},

Here is how I serialize it:

var json = JsonConvert.SerializeObject(input, Formatting.Indented);

What can I do to get Json.Net to serialize the dictionary?

From your comments you said that CESubnetCache is being serialized as an empty object, and you expected that the dictionary inside it would be serialized. The reason the dictionary is not getting serialized is because the base class is using opt-in semantics, as indicated by the [JsonObject(MemberSerialization.OptIn)] attribute on it. That means that no members of that class will be serialized unless you also mark them with [JsonProperty] attributes.

Try adding [JsonProperty("Items")] to the dictionary member, and that should solve the problem:

[JsonObject(MemberSerialization.OptIn)]
public abstract class CECacheBase<T>
{
    ...
    [JsonProperty("Items")]
    protected ConcurrentDictionary<string, T> items = new ConcurrentDictionary<string, T>();
    ...
}

I should also mention that if you were to remove the [JsonObject(MemberSerialization.OptIn)] attribute from the class, the dictionary still would not be serialized without the [JsonProperty] attribute in this case, because it is protected rather than public . Json.Net only serializes public members by default. So, either way, you need the [JsonProperty] attribute here.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM