J'essaie de sérialiser une hiérarchie de classe à une chaîne JSON en utilisant Mon problème est que les espaces de noms sont longs et ils battent la chaîne JSON.
J'aimerais d'en quelque sorte intervenir avec la sérialisation et la sortie ceci à la place: p>
et sur la désérialisation interviennent à nouveau pour pointer vers l'espace de nom correct (que je connais en runtime). p>
Y a-t-il un moyen de faire une telle chose? p> DatacontractJsonSerializer code>, dans un service WCF.
Le comportement par défaut de série Serializing Une classe dérivée consiste à ajouter la paire de valeurs de clé suivante à l'objet: p>
"__ type": "Nom de classe: #Namespace" code> p>
"__ type": "Nom de classe" code> p>
6 Réponses :
Cette page décrit les circonstances sous lesquelles la propriété __Type est émise . En bref, dans WCF, si vous utilisez un type dérivé, et un atticule connu, vous allez obtenir une propriété __Type.
Exemple: p>
suppose p> Ce code génère une propriété __Type: p> Mais ce code ne: p> Notez que le deuxième snip utilise un DCJS avec le même type que l'objet étant sérialisé. P> Pour éviter le __type N'utilisez pas de types dérivés, ou d'être précis, utilisez un sérialisateur saisi sur le type que vous êtes en série. Si la sérialisation est en cours d'exécution implicitement par une méthode WCF, le procédé doit alors être saisi de manière appropriée. Dans mon exemple, cela signifie que vous devez utiliser un type de retour d'abonné "et non le type parent" Personne ". p> Le __type est émis dans le flux JSON par la méthode de WriteServertypeAbute (privée) WrireServerTypeTtribue sur le
Système (interne ).Runtime.Serialization.json.xmljsonwriter classe. Il n'y a pas de manière publique, documentée, prise en charge de modifier que, autant que je sache. P> Pour éviter cela, vous devez peut-être renvoyer une chaîne de la méthode WCF, effectuer la sérialisation vous-même, et post-traiter le JSON émis. p> Si cela ne vous dérange pas de la chose __type, mais je veux simplement supprimer l'espace de nom de qualification de la valeur, puis mettez vos types dans l'espace de noms global. En d'autres termes, mettez-les en dehors de n'importe quel espace de noms code> DÉCLARATION DU CODE. p> Exemple: lorsque les types de données résident dans un espace de noms, et lorsque j'ai utilisé un type dérivé, le JSON sérialisé ressemble à ceci: p> quand le Types de données réside dans l'espace de noms global, il ressemble à ceci: p>
Remarque: j'ai tapé cette réponse ci-dessous et réalisa plus tard que DatacontracTresolver n'est actuellement pas pris en charge avec DatacontractJsonSonerializer. Il peut bientôt être avec la prochaine version du cadre, cependant. Ceci est également utile si vous regardez plus que JSON. P>
** p>
Vous pouvez le faire avec un DataContracTresolver, qui vous permet de mapper des types à XSI: type (__type) Informations et inversement de manière personnalisée. P>
Pour ce faire, consultez Ce blog post sur DatacontracTresolver , plus Ce sujet conceptuel , plus Cet exemple P>
Ajout du paramètre d'espace de noms au contrat de données fait l'affaire.
[Datacontract (espace de noms = "")] code> p>
Cela a supprimé la partie d'espace de noms de l'attribut, mais pas le côlon qui traîne le nom de classe. Donc, +1 pour des économies, mais toujours une solution complète.
La réponse de Cheeso était excellente. J'ai découvert un raffinement pour nettoyer le champ __type cependant:
Plutôt que de supprimer votre sous-classe de son espace de noms, vous pouvez ajouter une propriété comme ci-dessous: p> vous encore Soyez coincé avec le nom laid "__type" mais j'ai trouvé que parce que je retourne une liste de sous-types, je voulais spécifier le nom de type de toute façon. Vous pouvez même retourner une valeur de "" pour réduire davantage la taille de la réponse. Vous pouvez également déclarer la propriété comme suit: P> public string __type
J'ai constaté que cette solution exige que le champ "__type" soit le premier élément de la sérialisation JSON. Cela rompt avec la spécification JSON, mais plus important encore, je dois maintenant trouver un moyen de commander les champs de la sérialisation.
@cheeso a écrit:
Pour éviter cela, vous auriez peut-être besoin de renvoyer une chaîne de la WCF méthode, effectuez la sérialisation vous-même et post-traiter le JSON émis. p> BlockQuote>
Voici comment j'ai mis en œuvre ce post-traitement. Je pensais que je le posterais ici Jic ça pourrait aider quelqu'un d'autre. P>
Premier partie de la chaudron pour montrer comment je génère ma chaîne JSON: P>
// This strips out that unsuppressable __type clutter generated by the KnownType attributes Attribute[] attrs = Attribute.GetCustomAttributes(xyz.GetType()); foreach (Attribute attr in attrs) { if (attr is KnownTypeAttribute) { KnownTypeAttribute a = (KnownTypeAttribute)attr; string find = "\"__type\":\"" + a.Type.ReflectedType.Name + "." + a.Type.Name + ":#" + a.Type.Namespace + "\","; json = json.Replace(find, ""); } }
Notez que vous devez l'appeler récursivement si vous avez plus d'un niveau d'objets personnalisés dans le fichier complet. En fin de compte, je viens de le dépouiller avec une regex: "\" __ type \ "\\ s *: \\ s * \" [^ \ "] + \" \\ s * ,? \\ s * " code>
Il y a quelques fois j'ai décidé de ce problème. J'utilise DatacontractjsonSonSerializer Vous aurez __Type dans JSON, si votre méthode de sérialisation a un paramètre de classe de base, mais vous lui donnez la sous-classe comme paramètre. Plus de détails:
public static void ReadType<T>(T type) { Console.WriteLine(ToJson(type)); }
Et si le problème est le sous-type utilisé à cet objet, cependant?
L'envoi sans l'espace de noms semble terriblement hacky, bien que.Je soit juste laissé tomber tout à fait, ou pas du tout ...
@Nyerguds Cela dépend des priorités ... Si, par exemple, vous communiquez avec un périphérique de bande passante extrêmement faible, vous devez faire des compromis ...