26

I have a class

public class Order
{
   public int Id { get; set; }
   public string ShippingMethod { get; set; }
}

and I want to deserialize a JSON data below into the above class/object

string json = @"{
  'Id': 1,
  'ShippingMethod': {
     'Code': 'external_DHLExpressWorldwide',
     'Description': 'DHL ILS Express Worldwide'
  }
}";

My idea is that ShippingMethod in JSON is a object, but I just want to get to ShippingMethod.Code (in JSON) that will pass into ShippingMethod as string in Order class during deserialization.

how can I accomplish that goal using Json.NET?

I believe I can accomlish it using CustomJsonConverter. But I get confused. The example in the docs just for WriteJson, but not ReadJson.

5
  • So Code and Description are inside ShippingMethod? How are serialized? Commented Nov 5, 2016 at 14:32
  • You just need to have "Id" and "Code" at the same level? Commented Nov 5, 2016 at 14:33
  • Yeah, that is my problem and what I want to accomplish Commented Nov 5, 2016 at 14:33
  • ShippingMethod is object in the json and string in C# class. How you can map this. You have to change the code as below. Commented Nov 5, 2016 at 14:42
  • @Aruna See my way to map it stackoverflow.com/questions/40439290/… Commented Nov 5, 2016 at 15:32

3 Answers 3

51

I just resolve my problem using JsonConverter as I mentioned above in my question. Below my complete code:

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

    [JsonConverter(typeof(ShippingMethodConverter))]
    public string ShippingMethod { get; set; }
}

public class ShippingMethodConverter : JsonConverter
{

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

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
        {
            return string.Empty;
        } 
        else if (reader.TokenType == JsonToken.String)
        {
            return serializer.Deserialize(reader, objectType);
        }
        else
        {
            JObject obj = JObject.Load(reader);
            if (obj["Code"] != null) 
                return obj["Code"].ToString();
            else 
                return serializer.Deserialize(reader, objectType);
        }
    }

    public override bool CanWrite
    {
        get { return false; }
    }

    public override bool CanConvert(Type objectType)
    {
        return false;
    }
}
Sign up to request clarification or add additional context in comments.

Comments

17
 dynamic o = JsonConvert.DeserializeObject(json);
 var order = new Order
 {
     Id = o.Id,
     ShippingMethod = o.ShippingMethod.Code
 };

Deserialize the object as dynamic and then fill the Order object by accessing to the dynamic object properties

4 Comments

+1 for this one. I think this is the best clean way without attribute pollution and new class creation :)
Thank you for your answer, but it not suitable if there are lot another properties
You haven't say that there are more properties to manage. To solve this you could add an Extension method that map once and then you can use it wherever you want. But also you solution seems ok, just to much line of code fortwo properties (in my opinion)
Yes, there look lot of code, but in real word it will keep your model clean.
15

You can use JsonProperty and JsonIgnore attributes to direct the deserialization process... So your model can be:

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

    [JsonIgnore]
    public string ShippingMethod
    {
        get
        {
            return (string)TempShippingMethod?["Code"];
        }
    }

    [JsonProperty("ShippingMethod")]
    private JObject TempShippingMethod { set; get; }
}

var res = JsonConvert.DeserializeObject<Order>(json);

6 Comments

Yeah, that just a tiny hack. I don't like this way, but I upvote :) as my respect to your answer
@Habibillah I didn't like your answer too, too cumbersome for a simple thing, But as my respect to your opinion, I posted a simplified version of my answer..
No worries :). The question is simple think, but my real word, with lot of property and bad json schema, it really worth. Example. saving an order, you must pass string, but for getting order detail, you got an object. And many more
I'd disagree this is a hack. JsonIgnore is designed for this kind of purpose - it means you don't have to re-write the serialization. Presumably, we're missing some context as to why this is not suitable for the OP.
When using [JsonProperty("...")] I'm getting the compiler error CS0616: 'JsonProperty' is not an attribute class. I need to use [JsonPropertyName("...")] instead. I'm on .Net 7.0
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.