Search code examples
c#jsonjson.net

Newtonsoft JSON rename the property name depends on another property


I have a class with the following fields.

public class Payment
{
    public string type { get; set; }
    public string issuer { get; set; }
    public string identifier { get; set; }
    public float price { get; set; }
}

The "type" field can be "Giftcard" or "Creditcard".
I want to serialize it depends on the "type" field.

{
   "type": "Giftcard",
   "giftcard_no": "111111111111",
   "giftcard_price": 100
}
{
   "type": "Creditcard",
   "issuer": "AMEX",
   "last_4_digits": "1000",
   "creditcard_price": 100
}

As you can see, the field names are different depends on the "type" field.
And "issuer" field is ignored in case of Giftcard.

I've found similar questions, but couldn't find the correct answer.
I will be appreciated for any help.

Thank you.


Solution

  • It sounds to me like what you want is different subclasses, using type to determine which one to use when deserializing. I've found that the JsonSubTypes package (GitHub repo) works very well for this.

    You'd have something like this:

    [JsonConverter(typeof(JsonSubtypes), "type")]
    [JsonSubtypes.KnownSubType(typeof(GiftCard), "Giftcard")]
    [JsonSubtypes.KnownSubType(typeof(CreditCard), "Creditcard")]
    public class Payment
    {
        [JsonProperty("type")]
        public virtual string Type { get; }
    }
    
    public class CreditCard : Payment
    {
        public override string Type => "Creditcard";
    
        [JsonProperty("issuer")
        public string Issuer { get; set; }
    
        // Etc, other properties
    }
    
    public class GiftCard : Payment
    {
        public override string Type => "Giftcard";
    
        [JsonProperty("giftcard_no")]
        public string GiftCardNumber { get; set; }
    
        // Etc, other properties
    }
    

    There are various different options for exactly how you register things - the README on the GitHub repo gives concrete examples, which is really useful.

    You'd then deserialize to Payment, but the returned value would be a reference to an instance of GiftCard or CreditCard.