Comment sérialiser un type anonyme C # en une chaîne JSON?

162

J'essaie d'utiliser le code suivant pour sérialiser un type anonyme en JSON:

var serializer = new DataContractJsonSerializer(thing.GetType());
var ms = new MemoryStream();
serializer.WriteObject(ms, thing);
var json = Encoding.Default.GetString(ms.ToArray()); 

Cependant, j'obtiens l'exception suivante lorsque cela est exécuté:

Le type '<> f__AnonymousType1`3 [System.Int32, System.Int32, System.Object []]' ne peut pas être sérialisé. Envisagez de le marquer avec l'attribut DataContractAttribute et de marquer tous ses membres que vous souhaitez sérialiser avec l'attribut DataMemberAttribute. Consultez la documentation de Microsoft .NET Framework pour les autres types pris en charge.

Je ne peux pas appliquer d'attributs à un type anonyme (pour autant que je sache). Existe-t-il une autre façon de faire cette sérialisation ou est-ce que je manque quelque chose?

JC Grubbs
la source

Réponses:

159

Essayez le JavaScriptSerializer au lieu de DataContractJsonSerializer

JavaScriptSerializer serializer = new JavaScriptSerializer();
var output = serializer.Serialize(your_anon_object);
Nick Berardi
la source
17
Trackback, il semble qu'il a été déconseillé dans SP1.
Biswanath
7
pour quelque chose d'aussi obsolète, il semble être utilisé dans de nombreux nouveaux frameworks Microsoft, y compris MVC. aspnet.codeplex.com/SourceControl/changeset/view/21528#266491
Nick Berardi
1
Comment inclure ce projet ia non-asp.net (application console)?
Alxandr
4
@Alxandr: Vous auriez besoin de référencer System.Web.Extensions.dllet d'ajouter une using System.Web.Script.Serialization;déclaration.
randomguy
1
Le problème @randomgui était que le type de sortie du projet était défini sur profil client.
Alxandr
75

Comme d'autres l'ont mentionné, Newtonsoft JSON.NET est une bonne option. Voici un exemple spécifique de sérialisation JSON simple:

return JsonConvert.SerializeObject(
    new
    {
       DataElement1,
       SomethingElse
    });

J'ai trouvé que c'était une bibliothèque très flexible et polyvalente.

Matthew Nichols
la source
14

Vous pouvez essayer mon ServiceStack JsonSerializer, c'est le sérialiseur .NET JSON le plus rapide du moment. Il prend en charge la sérialisation des DataContract, de tout type POCO, des interfaces, des objets à liaison tardive, y compris des types anonymes, etc.

Exemple de base

var customer = new Customer { Name="Joe Bloggs", Age=31 };
var json = customer.ToJson();
var fromJson = json.FromJson<Customer>(); 

Remarque: n'utilisez Microsofts JavaScriptSerializer que si les performances ne sont pas importantes pour vous, car j'ai dû les laisser en dehors de mes repères car il est jusqu'à 40x-100x plus lent que les autres sérialiseurs JSON.

Mythz
la source
7
J'utilise MS JavaScriptSerializer sur la pile MVC3 pour sérialiser des objets avec de petites quantités de données. C'est assez rapide dans ces cas, prenant moins d'une milliseconde pour faire ce dont j'ai besoin. La requête DB elle-même prend 50x-100x plus longtemps, donc ce n'est pas vraiment un goulot d'étranglement important dans ma situation.
Brian
2
L'optimisation prématurée est un ... Eh bien, vous savez.
Mathias Lykkegaard Lorenzen
1
Le lien "plus rapide du sérialiseur .NET JSON" est 404ing! De plus, cette réponse a plus de 5 ans et demi. Avez-vous une mise à jour sur les performances de divers sérialiseurs .NET JSON?
ErikE
11

Veuillez noter que cela date de 2008. Aujourd'hui, je dirais que le sérialiseur devrait être intégré et que vous pouvez probablement utiliser les attributs swagger + pour informer les consommateurs sur votre point de terminaison et renvoyer des données.


Je dirais que vous ne devriez pas sérialiser un type anonyme . Je connais la tentation ici; vous voulez générer rapidement des types jetables qui vont juste être utilisés dans un environnement de type lâche aka Javascript dans le navigateur. Pourtant, je créerais un type réel et le décorerais comme sérialisable. Ensuite, vous pouvez taper fortement vos méthodes Web. Bien que cela ne compte pas un iota pour Javascript, cela ajoute une auto-documentation à la méthode. Tout programmeur raisonnablement expérimenté pourra regarder la signature de la fonction et dire: "Oh, c'est du type Foo! Je sais à quoi cela devrait ressembler en JSON."

Cela dit, vous pouvez essayer JSON.Net pour effectuer la sérialisation. Je n'ai aucune idée si cela fonctionnera

Jason Jackson
la source
3
JSON.Net fonctionne très bien. Je dirais que vous ne devriez pas :), je pense que c'est assez légitime dans de nombreux cas.
aprilchild
2
Après avoir vu les types «à jeter» utilisés dans MVC, je peux voir quelques utilisations convaincantes. Je pense que c'est un outil très pratique à avoir dans votre boîte à outils .Net.
Matthew Whited
12
C'est un point sur lequel j'ai également adouci, en particulier dans le cas des types à consommation uniquement. Mais si l'objet effectue un voyage de retour vers le serveur ou est utilisé à plusieurs endroits, je pense toujours que la création d'un type entraînera moins de problèmes.
Jason Jackson
La désérialisation de style DataContract ne gère pas bien les types polymorphes. Vous devez écrire votre propre désérialiseur. Trop de maintenance du code.
micahhoover
Un cas d'utilisation où la sérialisation de types anonymes est utile est celui des tests unitaires pour les API Web.
howcheng
9

Le moyen le plus rapide que j'ai trouvé était le suivant:

var obj = new {Id = thing.Id, Name = thing.Name, Age = 30};
JavaScriptSerializer serializer = new JavaScriptSerializer();
string json = serializer.Serialize(obj);

Espace de noms: System.Web.Script.Serialization.JavaScriptSerializer

i31nGo
la source
2
Et pour la désérialisation:. . dynamic myObject = JsonConvert.DeserializeObject <dynamic> (sortie); . . référence: Newtonsoft.json.dll
i31nGo
2

Vous pouvez utiliser Newtonsoft.Json.

var warningJSON = JsonConvert.SerializeObject(new {
                warningMessage = "You have been warned..."
            });
Ahmet Arslan
la source
1

En supposant que vous l'utilisez pour un service Web, vous pouvez simplement appliquer l'attribut suivant à la classe:

[System.Web.Script.Services.ScriptService]

Ensuite, l'attribut suivant à chaque méthode qui doit renvoyer Json:

[ScriptMethod(ResponseFormat = ResponseFormat.Json)]

Et définissez le type de retour des méthodes sur "objet"

Paul
la source
Pour un service Web ASP standard [ScriptMethod (ResponseFormat = ResponseFormat.Json)] n'est pas nécessaire sur la méthode, [WebMethod] fera l'affaire. De plus, vous ne devez pas définir le type de retour sur objet, il peut et doit être fortement typé avec un type non complexe (c'est-à-dire peut être sérialisé).
row1
-1
public static class JsonSerializer
{
    public static string Serialize<T>(this T data)
    {
        try
        {
            DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
            var stream = new MemoryStream();
            serializer.WriteObject(stream, data);
            string jsonData = Encoding.UTF8.GetString(stream.ToArray(), 0, (int)stream.Length);
            stream.Close();
            return jsonData;
        }
        catch
        {
            return "";
        }
    }
    public static T Deserialize<T>(this string jsonData)
    {
        try
        {
            DataContractJsonSerializer slzr = new DataContractJsonSerializer(typeof(T));
            var stream = new MemoryStream(Encoding.UTF8.GetBytes(jsonData));
            T data = (T)slzr.ReadObject(stream);
            stream.Close();
            return data;
        }
        catch
        {
            return default(T);
        }
    }
}
harryovers
la source
Cela ne sérialise pas les types anonymes selon la question
Mark Sowul