3

I have some JSON that I want to deserialize into an instance of a C# class. However, the class does not have all the fields/properties matching the original JSON. I would like to be able to modify the property values in the class and then serialize it back to JSON with the remaining fields and properties from the original JSON still intact.

For example, let's say I have the following JSON:

{
    "name": "david",
    "age": 100,
    "sex": "M",
    "address": "far far away"
}

And I want to deserialize it into this class:

class MyClass 
{  
    public string name { get; set; }  
    public int age { get; set; }  
}

After deserializing, I set the following:

myClass.name = "John";
myClass.age = 200;

Now, I want to serialize it back to JSON and get this result:

{
    "name": "John",
    "age": 200,
    "sex": "M",
    "address": "far far away"
}

Is there a way to do this using Json.Net?

Brian Rogers
  • 125,747
  • 31
  • 299
  • 300
vkom
  • 233
  • 4
  • 12
  • It's not exactly what you're looking for but this is at least one solution, http://stackoverflow.com/questions/1207731/how-can-i-deserialize-json-to-a-simple-dictionarystring-string-in-asp-net – Shriike Nov 14 '14 at 19:49
  • 1
    Why don't you just add the properties to class? – Mikko Viitala Nov 14 '14 at 20:25
  • @MikkoViitala He might not know exactly what the other properties are, or they could be variable in name and number. – Brian Rogers Nov 14 '14 at 20:48
  • @BrianRogers that is correct. The actually JSON is really huge and only want to modify some fields in a strongly typed environment without having to define all the fields. I did come up with a solution which I will post it here in a sec – vkom Nov 14 '14 at 21:36

2 Answers2

5

You can use Json.Net's "extension data" feature to handle this.

Add a new Dictionary<string, object> property to your class and mark it with a [JsonExtensionData] attribute. (You can make it a private property if you don't want to affect the public interface of your class.) On deserialization, this dictionary will be filled with any data that doesn't match any of the other public properties of your class. On serialization, the data in the dictionary will be written back out to the JSON as properties of the object.

class MyClass
{
    public string name { get; set; }
    public int age { get; set; }

    [JsonExtensionData]
    private Dictionary<string, object> otherStuff { get; set; }
}

Here is a demo:

class Program
{
    static void Main(string[] args)
    {
        string json = @"
        {  
            ""name"": ""david"",
            ""age"": 100,
            ""sex"": ""M"",
            ""address"": ""far far away""
        }";

        MyClass obj = JsonConvert.DeserializeObject<MyClass>(json);

        Console.WriteLine("orig name: " + obj.name);
        Console.WriteLine("orig age: " + obj.age);
        Console.WriteLine();

        obj.name = "john";
        obj.age = 200;

        json = JsonConvert.SerializeObject(obj, Formatting.Indented);
        Console.WriteLine(json);
    }
}

Output:

orig name: david
orig age: 100

{
  "name": "john",
  "age": 200,
  "sex": "M",
  "address": "far far away"
}
Brian Rogers
  • 125,747
  • 31
  • 299
  • 300
0

Ok, so after posting the question, went to lunch, came back and I found the solution. Instead of using JSON.nets "extension data" I found that they have a "merge" function http://james.newtonking.com/archive/2014/08/04/json-net-6-0-release-4-json-merge-dependency-injection

IMO I think this is much cleaner and decided to go with this method.

Below is a sample I was writing

public class Cell
{
  public string Text { get; set; }
  public int ID { get; set; }
  public CellStyle Style { get; set; }
}

public class CellStyle
{
  public string BgColor { get; set; }
  public string TextColor { get; set; }
}

string json = @"{
  'Text': 'My Cell',
  'ID': 20,
  'TsID': 100,
  'Style':  {
              'BgColor' : 'Red',
              'TextColor' : 'Black',
              'Caption' : 'Help My Cell',
            }
}";

var orgCell = JsonConvert.DeserializeObject<Cell>(json);
orgCell.Style.TextColor = "White";
orgCell.Style.BgColor = "Blue";

var obj = JsonConvert.SerializeObject(orgCell);

JObject o1 = JObject.Parse(json);
JObject o2 = JObject.Parse(obj);

o1.Merge(o2, new JsonMergeSettings
{
  // union array values together to avoid duplicates
  MergeArrayHandling = MergeArrayHandling.Union
});

o1.ToString(); // gives me the intended string 
vkom
  • 233
  • 4
  • 12
  • 1
    Not sure why you consider this cleaner. In addition to being more convoluted, from a performance perspective, you're doing two additional parses and a merge. – David Peden Nov 14 '14 at 22:20
  • I'm actually not sure which method to use yet. I have concerns since the JSON itself has multiple nested layers and haven't fully tested either wyas. But at least I have options to solve the solution now – vkom Nov 14 '14 at 22:47