2012-05-02 1 views
1

J'utilise System.Net.Http.HttpClient, the version currently available in NuGet, pour récupérer des données d'un service au format json. Les données ressemble à peu près comme ceci:Comment utiliser ReadAsAsync <T> avec ce schéma de données?

{ 
    "schema": "Listing", 
    "data": { 
    "key": "28ba648c-de24-45d4-a7d9-70f810cf5438", 
    "children": [{ 
     "kind": "type1", 
     "data": { 
     "body": "Four score and seven years ago...", 
     "parent_id": "2qh3l", 
     "report_count": 0, 
     "name": "c4j6yeh" 
     } 
    }, { 
     "kind": "type3", 
     "data": { 
     "domain": "abc.def.com", 
     "flagged": true, 
     "category": "news", 
     "saved": false, 
     "id": "t3dz0", 
     "created": 1335998011.0 
     } 
    }] 
    } 
} 

J'utilise HttpContentExtensions.ReadAsAsync<T> pour désérialiser cette chaîne JSON dans un graphe d'objet. Les définitions de type ressemble à peu près comme ceci:

public class Response 
{ 
    public String schema { get;set; } 
    public ListingData data { get;set; } 
} 

public class ListingData 
{ 
    public string key { get;set; } 
    public List<OneItem> children { get;set; } 
} 

Voici le problème: je veux le type des éléments dans children varier en fonction de la propriété kind. Si kind est "type1" alors je veux désérialiser un objet de ... appelons-le Type1. Si kind est "type3" alors je veux un objet de type Type3.

Pour l'instant, je peux désérialiser un List<Type1> ou un List<Type3>, mais je ne sais pas comment dire à la logique de dé-sérialisation de faire la distinction entre les deux.

Je pourrais fusionner toutes les propriétés de l'objet de données "type1" et de l'objet de données "type3" en un seul type .NET. Mais le nombre de propriétés est suffisamment important pour que cela devienne salissant.

Si le nom de la propriété dans le JSON (dans ce cas data) était différent, je pourrais distinguer l'utiliser. Si, par exemple, les données ressemblaient à ceci:

"children": [{ 
     "kind": "type1", 
     "t1data": { ... } 
    }, { 
     "kind": "type3", 
     "t3data": { ... } 
    }] 

... alors que je pouvais faire quelque chose comme ça dans .NET:

public class OneItem 
{ 
    public string kind { get;set; } 
    public Type1 t1data { get;set; } 
    public Type3 t3data { get;set; } 
} 

Mais mon schéma de données ne ressemble pas à ça.

Est-il possible de choisir le type de désérialisation par le contenu des données? En d'autres termes, examinez la valeur d'une propriété (dans ce cas, kind) pour déterminer comment dé-sérialiser le contenu d'une autre propriété (dans ce cas, data).

Ou est-il possible d'injecter un filtre ou un transformateur qui agit sur le JSON avant que ReadAsAsync ne tente de le désérialiser?

Si oui, comment?

Répondre

0

Si vous êtes en train de faire un pré-traitement sur votre réponse et que vous pouvez utiliser Json.NET, vous devriez être capable de faire ce que vous voulez.

Compte tenu des classes suivantes:

public class Response 
{ 
    public string schema 
    { 
     get; 
     set; 
    } 

    public ListingData data 
    { 
     get; 
     set; 
    } 
} 

public class ListingData 
{ 
    public string key 
    { 
     get; 
     set; 
    } 

    public List<object> children 
    { 
     get; 
     set; 
    } 
} 

public class Type1 
{ 
    public string body 
    { 
     get; 
     set; 
    } 

    public string parent_id 
    { 
     get; 
     set; 
    } 

    public int report_count 
    { 
     get; 
     set; 
    } 

    public string name 
    { 
     get; 
     set; 
    } 
} 

public class Type3 
{ 
    public string domain 
    { 
     get; 
     set; 
    } 

    public bool flagged 
    { 
     get; 
     set; 
    } 

    public string category 
    { 
     get; 
     set; 
    } 

    public bool saved 
    { 
     get; 
     set; 
    } 

    public string id 
    { 
     get; 
     set; 
    } 

    public double created 
    { 
     get; 
     set; 
    } 
} 

Ce test passe:

[Test] 
public void RoundTrip() 
{ 
    var response = new Response 
         { 
          schema = "Listing", 
          data = new ListingData 
             { 
              key = "28ba648c-de24-45d4-a7d9-70f810cf5438", 
              children = new List<object> 
                  { 
                   new Type1 
                    { 
                     body = "Four score and seven years ago...", 
                     parent_id = "2qh3l", 
                     report_count = 0, 
                     name = "c4j6yeh" 
                    }, 
                   new Type3 
                    { 
                     domain = "abc.def.com", 
                     flagged = true, 
                     category = "news", 
                     saved = false, 
                     id = "t3dz0", 
                     created = 1335998011.0 
                    } 
                  } 
             } 
         }; 

    var jsonSerializerSettings = new JsonSerializerSettings 
             { 
              Formatting = Formatting.Indented, 
              TypeNameHandling = TypeNameHandling.Objects 
             }; 

    string serializedResponse = JsonConvert.SerializeObject(response, jsonSerializerSettings); 
    Console.WriteLine(serializedResponse); 
    var roundTrippedResponse = JsonConvert.DeserializeObject<Response>(serializedResponse, jsonSerializerSettings); 
    Assert.That(roundTrippedResponse.data.children.First().GetType(), Is.EqualTo(typeof(Type1))); 
    Assert.That(roundTrippedResponse.data.children.Last().GetType(), Is.EqualTo(typeof(Type3))); 
} 

La sortie sur la console est:

{ 
    "$type": "Test.Response, Test", 
    "schema": "Listing", 
    "data": { 
    "$type": "Test.ListingData, Test", 
    "key": "28ba648c-de24-45d4-a7d9-70f810cf5438", 
    "children": [ 
     { 
     "$type": "Test.Type1, Test", 
     "body": "Four score and seven years ago...", 
     "parent_id": "2qh3l", 
     "report_count": 0, 
     "name": "c4j6yeh" 
     }, 
     { 
     "$type": "Test.Type3, Test", 
     "domain": "abc.def.com", 
     "flagged": true, 
     "category": "news", 
     "saved": false, 
     "id": "t3dz0", 
     "created": 1335998011.0 
     } 
    ] 
    } 
} 

Donc, si vous pouvez transformer votre réponse reçue pour correspondre à celui du format attendu de Json.NET, cela fonctionnera.

Pour assembler tout cela, vous devez écrire un MediaTypeFormatter personnalisé et le passer à l'appel ReadAsAsync <>().

Questions connexes