How to implement class which can be used to de-serialize multiple level json?

51 views Asked by At

I have a json string like:

{
    "sn_request": {
        "sn_body": {
            "getExtensionlink": {
                "pid": null,
                "productUrl": "https://xx",
                "promotionId": null,
                "quanUrl": null,
                "subUser": null,
                "sugsUrl": null
            }
        }
    }
}

Due to that node getExtensionlink is dynamic, I implement the class like below:

public class SnRequest<T>
{
    public T sn_body { get; set; }
}

public class Root<T>
{
    public SnRequest<T> sn_request { get; set; }
}

public class GetExtensionlink<T>
{
    public T getExtensionlink { get; set; }
}

public class GetExtensionlinkTest
{
    [JsonProperty("pid")]
    public string Pid { get; set; }
    [JsonProperty("productUrl")]

    public string ProductUrl { get; set; }
    [JsonProperty("promotionId")]

    public string PromotionId { get; set; }
    [JsonProperty("quanUrl")]

    public string QuanUrl { get; set; }
    [JsonProperty("subUser")]

    public string SubUser { get; set; }
    [JsonProperty("sugsUrl")]

    public string SugsUrl { get; set; }
}

And then, deserialize it by code below:

var getExtensionlinkT = new GetExtensionlinkTest
{
    ProductUrl = @"https://m.suning.com/product/0071237944/000000012059477830.html?utm_campaign=1608091212288684183&utm_source=share-copyurl&utm_medium=2cd5ed46-copyurl"
};

var root = new Root<GetExtensionlink<GetExtensionlinkTest>>
{
    sn_request = new SnRequest<GetExtensionlink<GetExtensionlinkTest>>
    {
        sn_body = new GetExtensionlink<GetExtensionlinkTest>
        {
            getExtensionlink = getExtensionlinkT
        }                    
    }
};

var result = await client.PostAsJsonAsync<Root<GetExtensionlink<GetExtensionlinkTest>>, TestResponseBase<GetExtensionlink<GetExtensionlinkResponse>>>(@"https://xx", root);
            

But, this line Root<GetExtensionlink<GetExtensionlinkTest> make a little unacceptable.

I hope whether there is any way will make above code clean and reuseable.

1

There are 1 answers

0
Peter Csala On BEST ANSWER

How about making use of the JObject?

Simplified example

class Root
{
    public JObject Body { get; set; }
}

class X
{
    public int Id { get; set; }
}

class Y
{
    public string Desc { get; set; }
}

So I have a top entity and 2 different sub-entities.

Serialization

var a = new Root { Body = JObject.FromObject(new X {Id = 1}) };
var b = new Root { Body = JObject.FromObject(new Y {Desc = "Test"}) };

var jsonA = JsonConvert.SerializeObject(a);
var jsonB = JsonConvert.SerializeObject(b);

Console.WriteLine(jsonA);
Console.WriteLine(jsonB);

Here we are using the FromObject to convert sub-entities into JObjects.

The output

{"Body":{"Id":1}}
{"Body":{"Desc":"Test"}}

Deserialization

var rootA = JsonConvert.DeserializeObject<Root>(jsonA);
var rootB = JsonConvert.DeserializeObject<Root>(jsonB);

var x = rootA.Body.ToObject<X>();
var y = rootB.Body.ToObject<Y>();

Console.WriteLine(x.Id);
Console.WriteLine(y.Desc);

Here we are using the ToObject to convert JObjects sub-entities into.


With this approach you don't need to pass all the way down the generic parameter.