3

I using json .NET to deserialize my json string to my model. below is what I am trying to achieve, please advice what is best way ..

When there is no data my response looks like below json string = "{\"message\":\"SUCCESS\",\"result\":null}"

the result eventually is tied to a view. So when the response is null I would like to intialize my view with default model values. And so would like to call Default constructor on deserialization. Default constructor looks like below.

    public ProfileModel()
    {
        this.DefaultTab = DefaultTabOption.PROFILE;
        this.DataLoadPosition = new DataLoadPositionOptionsModel();
        this.DataLayout = new DataLayoutOptionsModel();
        this.NAData = new NADataOptionsModel();
        this.DataTable = new DataDisplayOptionsModel();
    }

But when there is data, the reponse looks like below.

{"message":"SUCCESS","result":{"dataLayout":{"vertical":false},"dataLoadPosition":{"cell":"B2","cursorLocation":false},"dataTable":{"decimalPts":1},"defaultTab":"BROWSE","naData":{"custom":"","naDataOption":"FORWARDFILL"}}}

In this case, I would like to call my parameterized constructor so that models are initialized correctly.

Deserialization code:

        using (StreamReader reader = new StreamReader(responseStream))
        {
           var t = JsonConvert.DeserializeObject<T>(reader.ReadToEnd());                
           return t;
        }

Where T is my main Model which initilialises multiple models. Below is the parameterized contructor.

public ProfileModel(DefaultTabOption defaultTabModel,
                    DataLoadPositionOptionsModel dataLoadPositionOption ,
                    DataLayoutOptionsModel dataLayoutOptios ,
                    NADataOptionsModel naDataOptions ,
                    DataDisplayOptionsModel dataTableOptions)
{
    this.DefaultTab = defaultTabModel;
    this.DataLoadPosition = dataLoadPositionOption;
    this.DataLayout = dataLayoutOptios;
    this.NAData = naDataOptions;
    this.DataTable = dataTableOptions;
}

What is they best way to deserialize so that default constructor is called when null and parameterized is call when not null. I tried the ConstructorHandling, NullValueHandling but I am not able to achieve desired results.

1 Answer 1

2

I've a little simplified your model

public sealed class ProfileModel
{
    public ProfileModel()
    {
        DataLayout = new DataLayoutOptionsModel();
    }

    public ProfileModel(DataLayoutOptionsModel dataLayout)
    {
        DataLayout = dataLayout;
    }

    public DataLayoutOptionsModel DataLayout { get; private set; }
}

public sealed class DataLayoutOptionsModel
{
    public bool Vertical { get; set; }
}

public class ResultModel
{
    public string Message { get; set; }
    public ProfileModel Result { get; set; }
}

To choose concrete constructor, you have to implement custom JsonConverter, for example

public sealed class MyJsonConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(ProfileModel).IsAssignableFrom(objectType);
    }

    public override object ReadJson(JsonReader reader,
        Type objectType,
        object existingValue,
        JsonSerializer serializer)
    {
        ProfileModel target;
        JObject jObject = JObject.Load(reader);

        JToken resultToken = jObject["Result"];
        //This is result null check
        if (resultToken.Type == JTokenType.Null)
        {
            target = new ProfileModel();
        }
        else
        {
            var optionsModel = resultToken["DataLayout"].ToObject<DataLayoutOptionsModel>();
            target = new ProfileModel(optionsModel);
        }

        serializer.Populate(jObject.CreateReader(), target);
        return target;
    }

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

So, result serialization looks like:

[Fact]
public void Test()
{
    string tinyJsonl = "{\"Message\":\"SUCCESS\",\"Result\":null}";
    var defaultProfile = JsonConvert.DeserializeObject<ProfileModel>(tinyJsonl, new MyJsonConverter());
    Assert.False(defaultProfile.DataLayout.Vertical);

    string fullJson = "{\"Message\":\"SUCCESS\",\"Result\":{\"DataLayout\":{\"Vertical\":true}}}";
    var customProfile = JsonConvert.DeserializeObject<ProfileModel>(fullJson, new MyJsonConverter());
    Assert.True(customProfile.DataLayout.Vertical);
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.