web-dev-qa-db-fra.com

Comment désérialiser une propriété JSON qui peut être deux types de données différents à l'aide de Json.NET

J'utilise Json.NET pour un projet sur lequel je travaille. À partir d'une API externe, je reçois du JSON avec des propriétés qui sont des objets, mais lorsqu'elles sont vides, "false" est transmis.

Par exemple:

data: {
    supplier: {
        id: 15,
        name: 'TheOne'
    }
}

Pourrait également être:

data: {
    supplier: false
}

Comment dois-je définir la propriété du fournisseur pour que le fournisseur soit désérialisé en objet fournisseur ou null.

En ce moment, j'ai:

public class Data {
   [JsonProperty("supplier")]
   public SupplierData Supplier { get; set; }
}
public class SupplierData {
    [JsonProperty("id")]
    public int Id { get; set; }
    [JsonProperty("name")]
    public string Name { get; set; }
}

Mais maintenant, en essayant de désérialiser lorsque le fournisseur a une valeur "fausse", cela échoue. Je voudrais que la propriété Supplier soit nulle lorsque la valeur JSON est 'false'.

J'espère que quelqu'un sait comment faire ça. Merci.

25
Marc Selman

Cela peut être résolu en créant un JsonConverter personnalisé pour votre classe SupplierData. Voici à quoi pourrait ressembler le convertisseur:

class SupplierDataConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(SupplierData));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JToken token = JToken.Load(reader);
        if (token.Type == JTokenType.Object)
        {
            return token.ToObject<SupplierData>();
        }
        return null;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        serializer.Serialize(writer, value);
    }
}

Pour l'utiliser, il vous suffit d'ajouter un [JsonConverter] attribut à la propriété Supplier dans votre classe Data comme ceci:

public class Data
{
    [JsonProperty("supplier")]
    [JsonConverter(typeof(SupplierDataConverter))]
    public SupplierData Supplier { get; set; }
}

Voici une démonstration du convertisseur en action. Notez que la démo suppose que vous disposez d'une sorte d'objet conteneur pour la propriété data, car le JSON dans votre question ne peut pas être autonome. J'ai défini une classe appelée RootObject à cet effet:

public class RootObject
{
    [JsonProperty("data")]
    public Data Data { get; set; }
}

Le code de démonstration réel suit:

class Program
{
    static void Main(string[] args)
    {
        string json = @"
        {
            ""data"": 
            {
                ""supplier"": 
                {
                    ""id"": 15,
                    ""name"": ""TheOne""
                }
            }
        }";

        Console.WriteLine("--- first run ---");
        RootObject obj = JsonConvert.DeserializeObject<RootObject>(json);
        DumpSupplier(obj.Data.Supplier);

        json = @"
        {
            ""data"": 
            {
                ""supplier"": false
            }
        }";

        Console.WriteLine("--- second run ---");
        obj = JsonConvert.DeserializeObject<RootObject>(json);
        DumpSupplier(obj.Data.Supplier);
    }

    static void DumpSupplier(SupplierData supplier)
    {
        if (supplier != null)
        {
            Console.WriteLine("Id: " + supplier.Id);
            Console.WriteLine("Name: " + supplier.Name);
        }
        else
        {
            Console.WriteLine("(null)");
        }
        Console.WriteLine();
    }
}

Et voici la sortie de ce qui précède:

--- first run ---
Id: 15
Name: TheOne

--- second run ---
(null)
34
Brian Rogers