简体   繁体   中英

Generating JSON from nested Dictionary in C#

I have the following Dictionary:

Dictionary<string, Dictionary<string, List<ChartData>>> data;

ChartData implementation looks like this:

   public struct ChartData
    {
        public long datetime;
        public double open;
        public double high;
        public double low;
        public double close;
        public ulong tick_volume;
        public int spread;
        public ulong volume;
    }

I want to generate JSON using the data I have in my data container. My data must look something like that:

{
    "EURUSD": [
        {
            "PROV": [
                {
                    "datetime":34534554,
                    "open":2.31,
                    "high":123,
                    "low":3213,
                    "close":213,
                    "tick_volume":2131,
                    "spread":2131,
                    "volume":3123
                },
                {
                    "datetime":34534554,
                    "open":2.31,
                    "high":123,
                    "low":3213,
                    "close":213,
                    "tick_volume":2131,
                    "spread":2131,
                    "volume":3123
                }
            ],
            "LMAX":[
                {
                    "datetime":34534554,
                    "open":2.31,
                    "high":123,
                    "low":3213,
                    "close":213,
                    "tick_volume":2131,
                    "spread":2131,
                    "volume":3123
                }
            ]
        }
    ],
    "BTCUSD":[
        {
            "PROV":[
                {
                    "datetime":34534554,
                    "open":2.31,
                    "high":123,
                    "low":3213,
                    "close":213,
                    "tick_volume":2131,
                    "spread":2131,
                    "volume":3123
                }
            ]
        }
    ]
}

The solution I have right now is this:

   var jsonObjectData= JObject.Parse(System.Text.Json.JsonSerializer.Serialize(data));
    var result = new JObject();

    result.Merge(jsonObjectData);

    var json = result.ToString(Newtonsoft.Json.Formatting.Indented);

But I don't see any correct data here.

Do you have any suggestions, that I could use to generate the required JSON from my nested Dictionary container?

I would appreciate any help.

Try using newtonsoft:

string output = JsonConvert.SerializeObject(data);

The major issue here is that by default, System.Text.Json.Serializer will NOT serialize fields. The solution from Amjad works because NewtonSoft serializes all fields and properties by default, as long as they are public .

The best practice advice for this is to change your model so that ChartData uses properties instead of fields :

public struct ChartData
{
    public long datetime { get;set; }
    public double open { get;set; }
    public double high { get;set; }
    public double low { get;set; }
    public double close { get;set; }
    public ulong tick_volume { get;set; }
    public int spread { get;set; }
    public ulong volume { get;set; }
}

Alternatively, if you do not want to use properties you can annotate the fields with the [JsonInclude] Attribute:

public struct ChartData
{
    [System.Text.Json.Serialization.JsonInclude]
    public long datetime;
    [System.Text.Json.Serialization.JsonInclude]
    public double open;
    [System.Text.Json.Serialization.JsonInclude]
    public double high;
    [System.Text.Json.Serialization.JsonInclude]
    public double low;
    [System.Text.Json.Serialization.JsonInclude]
    public double close;
    [System.Text.Json.Serialization.JsonInclude]
    public ulong tick_volume;
    [System.Text.Json.Serialization.JsonInclude]
    public int spread;
    [System.Text.Json.Serialization.JsonInclude]
    public ulong volume;
}

Either of those changes to the ChartData struct will include the content in the output of this code:

string json = System.Text.Json.JsonSerializer.Serialize(data);

There is another option, but it is widely considered an Anti-Pattern , that is to specify in the options that you want to include fields as well:

var options = new System.Text.Json.JsonSerializerOptions  
              { 
                  WriteIndented = true,
                  IncludeFields = true  
              };
string json = System.Text.Json.JsonSerializer.Serialize(data, options);

The IncludeFields setting is the easy option for this particular scenario as it doesn't require changes to the model, but doing this will include the fields of ALL nested objects that are being serialized, not just ChartData . This can lead to unexpected content being included. We recommend in.Net that you use public properties instead of fields , the reverse is also true, in class design, we expect that fields WILL NOT be included in serilization output.

The reasons and justifications on this are well understood and accepted by the .NET community so I won't go into detail here, but it is important to highlight again that you should respect the expected behaviours associated with properties and fields and that is why you should use properties or specifically annotate your fields to declare that you want the values to be included in serialization output.

You do not want to get into the habit of using the IncludeFields option in all of your serialization routines, as different data type may exhibit very different outputs and this may even affect deserialization processes.


As Amjab Saab has posted you could also use Newtonsoft's Newtonsoft's Json.NET instead of System.Text.Json however in this case the .NET team are specifically guiding us to design our classes better and are actively trying to enforce code standards and declarative design patterns, where Newtonsoft's approach is to be resilient to different design patterns agnostically. Due to this the .NET implementation is significantly faster and I encourage you to continue using System.Text.Json .

Note that James Newton-King, the author of Netwonsoft.Json is a key engineer in the team responsible for System.Text.Json . Think of System.Text.Json as an evolution that specifically has performance and conformance to JSON specification as a key goals. read more here: A Brief Comparison Between Newtonsoft.Json and System.Text.Json

I have prepared a fiddle showing one difference between the two libraries: https://dotnetfiddle.net/MSO1iA

Result using System.Text.Json.JsonSerializer.Serialize(data);

{
  "EURUSD": {
    "PROV": [
      {},
      {}
    ],
    "LMAX": [
      {}
    ]
  },
  "BTCUSD": {
    "PROV": [
      {}
    ]
  }
}

Result using System.Text.Json.JsonSerializer.Serialize(data, new JsonSerializerOptions { IncludeFields = true });

{
  "EURUSD": {
    "PROV": [
      {
        "datetime": 34534554,
        "open": 2.31,
        "high": 123,
        "low": 213,
        "close": 213,
        "tick_volume": 2131,
        "spread": 2131,
        "volume": 3123
      },
      {
        "datetime": 34534554,
        "open": 2.31,
        "high": 123,
        "low": 3213,
        "close": 213,
        "tick_volume": 2131,
        "spread": 2131,
        "volume": 3123
      }
    ],
    "LMAX": [
      {
        "datetime": 34534554,
        "open": 2.31,
        "high": 123,
        "low": 3213,
        "close": 213,
        "tick_volume": 2131,
        "spread": 2131,
        "volume": 3123
      }
    ]
  },
  "BTCUSD": {
    "PROV": [
      {
        "datetime": 34534554,
        "open": 2.31,
        "high": 123,
        "low": 3213,
        "close": 213,
        "tick_volume": 2131,
        "spread": 2131,
        "volume": 3123
      }
    ]
  }
}

Result using Newtonsoft.Json.JsonConvert.SerializeObject(data);

This is included as a comparison for devs who are just coming across to the current versions of.Net

{
  "EURUSD": {
    "PROV": [
      {
        "datetime": 34534554,
        "open": 2.31,
        "high": 123.0,
        "low": 213.0,
        "close": 213.0,
        "tick_volume": 2131,
        "spread": 2131,
        "volume": 3123
      },
      {
        "datetime": 34534554,
        "open": 2.31,
        "high": 123.0,
        "low": 3213.0,
        "close": 213.0,
        "tick_volume": 2131,
        "spread": 2131,
        "volume": 3123
      }
    ],
    "LMAX": [
      {
        "datetime": 34534554,
        "open": 2.31,
        "high": 123.0,
        "low": 3213.0,
        "close": 213.0,
        "tick_volume": 2131,
        "spread": 2131,
        "volume": 3123
      }
    ]
  },
  "BTCUSD": {
    "PROV": [
      {
        "datetime": 34534554,
        "open": 2.31,
        "high": 123.0,
        "low": 3213.0,
        "close": 213.0,
        "tick_volume": 2131,
        "spread": 2131,
        "volume": 3123
      }
    ]
  }
}

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