Home > other >  How to deserialize raw json field to model using Newtonsoft?
How to deserialize raw json field to model using Newtonsoft?

Time:11-24

So my json data is coming as string like following:

    { "name":"aaa", "sub": "{"x":"sss", "y":"eee"}" }
    

Sub field is a raw json string here.

My model is like following.

    class Main
    {
        public string Name { get;set;}
        public Sub Sub { get;set;}
    }

    class Sub
    {
        public string X { get;set;}
        public string Y { get;set;}
    }

I want to deserialize it like following:

var response = Encoding.UTF8.GetString(bytes); // getting data.
var jsonString = JsonConvert.Deseialize(response).ToString(); // to string.
var model = JsonConvert.Deserialize<Main>(jsonString); // error

The last step throws exception, like "string can not cast to Main" class.

CodePudding user response:

It sounds like you need a 2-step deserialization. If the value of sub is a string then it's a string, not a Sub instance. That string may be a JSON representation of a Sub instance, but that's another deserialization altogether.

First deserialize into the type represented by the whole object:

class Main
{
    public string Name { get;set; }
    public string Sub { get;set; }
}

and:

var mainObj = JsonConvert.DeserializeObject<Main>(response);

Then mainObj.Sub would contain the JSON string for your next type:

class Sub
{
    public string X { get;set; }
    public string Y { get;set; }
}

Which you can deserialize the same way:

var subObj = JsonConvert.DeserializeObject<Sub>(mainObj.Sub);

Overall the process of deserializing a JSON string to an object is the same. You just have to do it twice when you have two JSON strings.

CodePudding user response:

Assuming your question has a typo and you meant to escape the double quotes, e.g.:

{ "name":"aaa", "sub": "{\"x\":\"sss\", \"y\":\"eee\"}" }

Then you can achieve this with a custom converter. For example:

public class NestedJsonConverter : JsonConverter
{
    public override bool CanConvert(Type objectType) => true;

    public override object? ReadJson(JsonReader reader, Type objectType, 
        object? existingValue, JsonSerializer serializer)
    {
        // Get the raw string
        var s = serializer.Deserialize<string>(reader);

        // Deserialise into the correct type
        return JsonConvert.DeserializeObject(s, objectType);
    }

    public override void WriteJson(JsonWriter writer, object? value, 
        JsonSerializer serializer)
            => throw new NotImplementedException();
}

And change your model to add the attribute:

class Main
{
    public string Name { get; set; }
    
    [JsonConverter(typeof(NestedJsonConverter))]
    public Sub Sub { get; set; }
}

Now you can simply deserialise like this:

var result = JsonConvert.DeserializeObject<Main>(jsonString);
  • Related