Je reçois des données JSON à partir d'un service Web. il me fournit des DONNÉES DE FORMULAIRE avec différentes questions et réponses. chaque réponse est un objet c # différent . J'essaie de trouver le meilleur moyen de mapper les RÉPONSES pour corriger l'objet c #.
par exemple si l'ID de la question est "37" alors c'est un objet d'adresse.
I avoir une chaîne JSON comme dans ce format ci-dessous
foreach (var a in item.answers)
{
// pass the ANSWER OBJECT (dynamic data type) to function
createNewApplication(System.Convert.ToInt16(a.Key), a.Value.answer,ref app);
}
private void createNewApplication(int key, dynamic value,ref HcsApplicant app)
{
if (key == 4) // data is plain string
app.yourPhone = value;
if (key == 8)
app.yourEmail = value;
if (key==37) // data is a object
app.address = value.ToObject<address>();
}
et il correspond à la propriété c # suivante
public class answer
{
public string name { get; set; }
public dynamic answer { get; set; }
}
Ensuite, j'ai un générique Classe de réponse
public Dictionary<int, answer> answers{ get; set; }
si vous regardez les données ANSWER de json, vous verrez leur différence pour chaque question. par exemple, une réponse serait ADDRESS OBJECT, l'autre réponse serait l'objet FIRST & LAST NAME.
Ma question est, comment puis-je désérialiser automatiquement json en objets / propriétés corrects? Je peux créer différents objets POCO, tels que l'adresse et le ProfileName, mais comment les mapper automatiquement pour corriger l'objet / la propriété.
EDIT:
En boucle toutes les réponses
"answers": {
"37": {
"name": "yourAddress37",
"order": "6",
"sublabels": "{\"cc_firstName\":\"First Name\",\"cc_lastName\":\"Last Name\",\"cc_number\":\"Credit Card Number\",\"cc_ccv\":\"Security Code\",\"cc_exp_month\":\"Expiration Month\",\"cc_exp_year\":\"Expiration Year\",\"addr_line1\":\"Street Address\",\"addr_line2\":\"Street Address Line 2\",\"city\":\"City\",\"state\":\"State \\/ Province\",\"postal\":\"Postal \\/ Zip Code\",\"country\":\"Country\"}",
"text": "Your Home Address:",
"type": "control_address",
"answer": {
"addr_line1": "148 east 38st ",
"addr_line2": "",
"city": "Brooklyn ",
"state": "Ny",
"postal": "11203",
"country": ""
},
"prettyFormat": "Street Address: 148 east 38st <br>City: Brooklyn <br>State / Province: Ny<br>Postal / Zip Code: 11203<br>"
},
"38": {
"name": "emergencyContact",
"order": "9",
"sublabels": "{\"prefix\":\"Prefix\",\"first\":\"First Name\",\"middle\":\"Middle Name\",\"last\":\"Last Name\",\"suffix\":\"Suffix\"}",
"text": "Emergency Contact Name:",
"type": "control_fullname",
"answer": {
"first": "Pauline ",
"last": "Sandy "
},
"prettyFormat": "Pauline Sandy "
}
}
Cette approche est-elle correcte? une façon plus propre de le faire?
3 Réponses :
Créez un constructeur pour chaque type de réponse qui se construit en analysant une chaîne d'objet JSON. Faites en sorte que toutes les réponses implémentent une interface, par ex. Je réponds. Mappez tous les constructeurs (en tant que fonctions) aux ID de question correspondants dans un dictionnaire. Enfin, parcourez les questions, appelez chaque constructeur et placez-les peut-être dans un nouveau dictionnaire. Exemple de code:
interface IAnswer { };
public class ExampleAnswer : IAnswer
{
public ExampleAnswer(String JSONObject)
{
// Parse JSON here
}
}
delegate IAnswer AnswerConstructor(String JSONObject);
Dictionary<int, AnswerConstructor> Constructors = new Dictionary<int, AnswerConstructor>()
{
{1234, ((AnswerConstructor)(json => new ExampleAnswer(json)))}
// Add all answer types here
};
Dictionary<int, IAnswer> ParseAnswers(Dictionary<int, String> JSONObjects)
{
var result = new Dictionary<int, IAnswer>();
foreach (var pair in JSONObjects)
result.Add(pair.Key, Constructors[pair.Key](pair.Value));
return result;
}
Edit: Regardez la réponse de Matt pour quelques bonnes options pour analyser JSON.
Edit2, En réponse à votre modification: Cela ressemble à une bonne façon de le faire! Je pense que c'est mieux que ma réponse, car vous pouvez conserver toutes les informations de type, contrairement à ma méthode.
La seule chose que je vois que vous voudrez peut-être changer est d'utiliser else if ou switch au lieu de plusieurs ifs. Cela pourrait améliorer les performances si vous avez de nombreuses réponses.
Vous avez plusieurs options:
Désérialisation en un objet dynamique à l'aide du package System.Web selon cette réponse ou le package JSON.Net selon cette réponse puis utilisez les vérifications conditionnelles / l ' opérateur de propagation nul a> pour accéder à une propriété.
Désérialisez automatiquement jusqu'au niveau où il y a des différences, puis disposez d'un code pour désérialiser manuellement les propriétés qui sont différentes dans les types POCO corrects sur votre objet désérialisé parent.
Avec les approches 2 et 3, vous pouvez écrire une méthode d'aide plus agréable sur votre POCO qui inspecte les propriétés des objets et renvoie un résultat qui serait le type qui a été défini (je recommanderais de renvoyer un Enum) par exemple:
public PropertyTypeEnum GetPropertyType(MyPocoClass myPocoClass)
{
if (myPocoClass.PropertyOne != null)
{
return PropertyTypeEnum.TypeOne;
}
else if (...)
{
return PropertyTypeEnum.TypeN
}
else
{
// probably throw a NotImplementedException here depending on your requirements
}
}
Ensuite, dans votre code pour utiliser l'objet, vous pouvez utiliser l'Enum retourné pour activer les chemins logiques de votre code.
revoir l'EDIT s'il vous plaît.
Personnellement, je n'aime pas toutes les options qui impliquent une analyse personnalisée et une recherche directe sur les questions.
Vous pouvez utiliser la désérialisation partielle via classe JToken .
Déclarez simplement votre dictionnaire réponses comme tel :
public class Address
{
public string Name { get; set; }
// all the othe properties
// ....
public static Address From(Dictionary<int, JToken> answers)
{
return answers?.TryGetValue(37, out var address) ?? false
? address?.ToObject<Address>()
: null;
}
}
// so you can just write:
var address = Address.From(answers);
Et chaque fois que vous avez besoin de la page d'adresse, vous pouvez simplement faire Answers [37] .ToObject () . La façon dont vous parvenez à appeler cette méthode dépend du reste de votre code, mais vous pouvez l'intégrer dans des propriétés, dans un gros commutateur, dans plusieurs méthodes, une pour chaque classe. Une option que j'aime est d'avoir une méthode statique From dans chaque classe désérialisable:
public Dictionary<int, JToken> Answers{ get; set; }
En remarque, rappelez-vous que les paramètres de désérialisation par défaut pour Json.Net est insensible à la casse, vous pouvez donc désérialiser la propriété name de JSON en une propriété Name plus idiomatique sur vos POCO.