简体   繁体   中英

JSON serialization using newtonsoft in C#

I have the following model structure.

 public class ReferenceData
    {
        public string Version { get; set; }

        public List<DataItem> Data { get; set; }
    }


    public class DataItem
    {
        public Dictionary<string, string> Item { get; set; }
    }

In the dictionary i'm adding the key value pair and serializing with KeyValuePairConverter setting.

var settings = new JsonSerializerSettings
                {
                    ContractResolver = new CamelCasePropertyNamesContractResolver(),
                    NullValueHandling = NullValueHandling.Ignore,
                    Converters = new List<JsonConverter>() { new KeyValuePairConverter() }
                };

var object =  Newtonsoft.Json.JsonConvert.SerializeObject(
                    referenceData,
                    Formatting.None,
                    settings
                    );

And the output is,

 {  
       "data":[  
          {  
             "item":{  
                "ShortDescription":"Lorem ipssumm",
                "Title":"some text",
                "PlanType":"ZEROP",
             }
          },
           {  
             "item":{  
                "ShortDescription":"Lorem ipssumm",
                "Title":"some text",
                "PlanType":"ZEROP",
             }
          },
          {  
             "item":{  
                "ShortDescription":"Lorem ipssumm",
                "Title":"some text",
                "PlanType":"ZEROP",
             }
          }
       ]
    }

If we don't want item to be showed in the serialized string, what setting needs to be done in JsonSerializerSettings or is there any other way to do that.

Please note that i can not change the model structure as it is required.

output should be :

{  
   "data":[  
      {  
         "ShortDescription":"Lorem ipssumm",
         "Title":"some text",
         "PlanType":"ZEROP"
      },
      {  
         "ShortDescription":"Lorem ipssumm",
         "Title":"some text",
         "PlanType":"ZEROP"
      },
      {  
         "ShortDescription":"Lorem ipssumm",
         "Title":"some text",
         "PlanType":"ZEROP"
      }
   ]
}

You do not need nested generic collections if you use Json.NET 5.0 release 5 or later version. You can use JsonExtensionDataAttribute so that Item dictionary's keys and values will be serialized as a part of parent object.

public class ReferenceData
{
    public string version { get; set; }
    public List<DataItem> data { get; set; }
}

public class DataItem
{   
    [JsonExtensionData]
    public IDictionary<string, object> item { get; set; }
}

// ...

var referenceData = new ReferenceData {
    version = "1.0",
    data = new List<DataItem> {
        new DataItem {
            item = new Dictionary<string, object> {
                {"1", "2"},
                {"3", "4"}
            }
        },
        new DataItem {
            item = new Dictionary<string, object> {
                {"5", "8"},
                {"6", "7"}
            }
        }
    }
};

Console.WriteLine(JsonConvert.SerializeObject(referenceData));

Pay attention that you need Dictionary<string, object> instead of Dictionary<string, string> .

Here is the result I get:

{
  "version": "1.0",
  "data": [
    {
      "1": "2",
      "3": "4"
    },
    {
      "5": "8",
      "6": "7"
    }
  ]
}

Obviously, you can remove Version property to get the expected result.

Read more here: http://james.newtonking.com/archive/2013/05/08/json-net-5-0-release-5-defaultsettings-and-extension-data

If you change like this result will be what you expected;

public class ReferenceData
{
    public string Version { get; set; }

    public List<Dictionary<string, string>> Data { get; set; }
}

possible other solution is;

ReferenceData r = new ReferenceData();

r.Data = new List<DataItem>();

r.Data.Add(new DataItem { Item = new Dictionary<string, string>() { { "1", "2" }, { "3", "4" } } });



var anon = new
{
    data = r.Data.ToList().Select(x =>
        {
            dynamic data = new ExpandoObject();

            IDictionary<string, object> dictionary = (IDictionary<string, object>)data;

            foreach (var key in x.Item.Keys)
                dictionary.Add(key, x.Item[key]);

            return dictionary;
       }
    )
};

var result = JsonConvert.SerializeObject(anon);

result :

{
  "data": [
    {
      "1": "2",
      "3": "4"
    }
  ]
}

If you can't change the C# can use you a View model and use an appropriate structure. It's probably simpler than changing JSON settings, easier to return to and more explicit:

public class ReferenceData
{
    public string Version { get; set; }
    public List<Dictionary<string, string>> Data { get; set; }
}

Should serialise as you require.

You could implement a custom behaviour as follows:

class Program {
    static void Main(string[] args) {
        var referenceData = new ReferenceData() {
            Data = new List<DataItem>() {
                new DataItem(){
                    Item = new Dictionary<string,string>()  {
                        {"ShortDescription", "Lorem ipssumm"},
                        {"Title", "some text"},
                        {"PlanType", "ZEROP"},
                    }
                },
                new DataItem(){
                    Item = new Dictionary<string,string>()  {
                        {"ShortDescription", "Lorem ipssumm"},
                        {"Title", "some text"},
                        {"PlanType", "ZEROP"},
                    }
                },
                new DataItem(){
                    Item = new Dictionary<string,string>()  {
                        {"ShortDescription", "Lorem ipssumm"},
                        {"Title", "some text"},
                        {"PlanType", "ZEROP"},
                    }
                }
            }
        };

        var settings = new JsonSerializerSettings {
            ContractResolver = new CamelCasePropertyNamesContractResolver(),
            NullValueHandling = NullValueHandling.Ignore,
            Converters = new List<JsonConverter>() { new KeyValuePairConverter(), new CustomJsonSerializableConverter() }
        };

        File.WriteAllText("hello.json", Newtonsoft.Json.JsonConvert.SerializeObject(
            referenceData,
            Formatting.Indented,
            settings
        ));
    }
}

public class ReferenceData {
    public string Version { get; set; }
    public List<DataItem> Data { get; set; }
}


[CustomJsonSerializable]
public class DataItem {
    public Dictionary<string, string> Item { get; set; }

    public static void WriteJson(JsonWriter writer, DataItem value, JsonSerializer serializer) {
        serializer.Serialize(writer, value.Item);
    }

    public static DataItem ReadJson(JsonReader reader, DataItem existingValue, JsonSerializer serializer) {
        DataItem result = new DataItem();
        result.Item = serializer.Deserialize<Dictionary<string, string>>(reader);
        return result;
    }
}

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
public class CustomJsonSerializableAttribute : Attribute {
    public readonly string Read;
    public readonly string Write;

    public CustomJsonSerializableAttribute()
        : this(null, null) {
    }

    public CustomJsonSerializableAttribute(string read, string write) {
        this.Read = read;
        this.Write = write;
    }
}

public class CustomJsonSerializableConverter : JsonConverter {
    public override bool CanConvert(Type objectType) {
        return objectType.GetCustomAttribute(typeof(CustomJsonSerializableAttribute), false) != null;
    }

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

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {
        if(value != null) {
            var t = value.GetType();
            var attr = (CustomJsonSerializableAttribute)t.GetCustomAttribute(typeof(CustomJsonSerializableAttribute), false);
            var @delegate = t.GetMethod(attr.Write ?? "WriteJson", new Type[] { typeof(JsonWriter), t, typeof(JsonSerializer) });
            @delegate.Invoke(null, new object[] { writer, value, serializer });
        } else {
            serializer.Serialize(writer, null);
        }
    }

    public override bool CanRead {
        get {
            return true;
        }
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
        var t = existingValue.GetType();
        var attr = (CustomJsonSerializableAttribute)t.GetCustomAttribute(typeof(CustomJsonSerializableAttribute), false);
        var @delegate = t.GetMethod(attr.Read ?? "ReadJson", new Type[] { typeof(JsonReader), t, typeof(JsonSerializer) });
        return @delegate.Invoke(null, new object[] { reader, existingValue, serializer });
    }
}

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