tugberk
tugberk

Reputation: 58444

Deserialize known and unknown JSON fields into a CLR object with JSON.NET

I have the following JSON payload:

{
    "id": 1,
    "foo": "bar",
    "bar": "foo",
    "attr_1": ["foo", "bar"],
    "attr_2": ["foo2", "bar2"]
}

I also have the following CLR object:

public class Obj
{
    public int Id { get; set; }
    public string Foo { get; set; }
    public string Bar { get; set; }

    [JsonExtensionData]
    public IDictionary<string, string[]> Properties { get; set; }
}

If I try to deserialize it, it fails:

using (FileStream file = File.Open(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "file.txt"), FileMode.Open))
using (StreamReader reader = new StreamReader(file))
{
    Obj foo = JsonConvert.DeserializeObject<Obj>(reader.ReadToEnd());
}

There is already an answer to a similar question. However, it's not a solution to read and write each field one by one. What is the best way for me to deserialize leftover fields into IDictionary<string, string[]>?

Upvotes: 3

Views: 1870

Answers (1)

Ufuk Hacıoğulları
Ufuk Hacıoğulları

Reputation: 38478

This line in Json.NET source code enforces the value type to be JToken. I think easiest way is to create another type for serialization.

public class SerializationModel
{
    public int Id { get; set; }
    public string Foo { get; set; }
    public string Bar { get; set; }

    [JsonExtensionData]
    public IDictionary<string, JToken> Properties { get; set; }
}

class Model
{
    public int Id { get; set; }
    public string Foo { get; set; }
    public string Bar { get; set; }
    public Dictionary<string, string[]> Properties { get; set; }
}

[Test]
public void DeserializeTest()
{
    string data = File.ReadAllText("data.txt");
    SerializationModel serializationModel = JsonConvert.DeserializeObject<SerializationModel>(data);

    Model model = new Model
    {
        Id = serializationModel.Id,
        Foo = serializationModel.Foo,
        Bar = serializationModel.Bar,
        Properties = serializationModel.Properties.ToDictionary(item => item.Key, pair => pair.Value.ToObject<string[]>())
    };

}

Upvotes: 3

Related Questions