Comment obtenir du JSON formaté en .NET en utilisant C #?

256

J'utilise l'analyseur .NET JSON et je souhaite sérialiser mon fichier de configuration afin qu'il soit lisible. Donc au lieu de:

{"blah":"v", "blah2":"v2"}

J'aimerais quelque chose de plus agréable comme:

{
    "blah":"v", 
    "blah2":"v2"
}

Mon code est quelque chose comme ceci:

using System.Web.Script.Serialization; 

var ser = new JavaScriptSerializer();
configSz = ser.Serialize(config);
using (var f = (TextWriter)File.CreateText(configFn))
{
    f.WriteLine(configSz);
    f.Close();
}
Stephen Kennedy
la source

Réponses:

257

Vous allez avoir du mal à accomplir cela avec JavaScriptSerializer.

Essayez JSON.Net .

Avec des modifications mineures de l'exemple JSON.Net

using System;
using Newtonsoft.Json;

namespace JsonPrettyPrint
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            Product product = new Product
                {
                    Name = "Apple",
                    Expiry = new DateTime(2008, 12, 28),
                    Price = 3.99M,
                    Sizes = new[] { "Small", "Medium", "Large" }
                };

            string json = JsonConvert.SerializeObject(product, Formatting.Indented);
            Console.WriteLine(json);

            Product deserializedProduct = JsonConvert.DeserializeObject<Product>(json);
        }
    }

    internal class Product
    {
        public String[] Sizes { get; set; }
        public decimal Price { get; set; }
        public DateTime Expiry { get; set; }
        public string Name { get; set; }
    }
}

Résultats

{
  "Sizes": [
    "Small",
    "Medium",
    "Large"
  ],
  "Price": 3.99,
  "Expiry": "\/Date(1230447600000-0700)\/",
  "Name": "Apple"
}

Documentation: sérialiser un objet

Sky Sanders
la source
Il y a aussi un exemple de formatage de la sortie json sur son blog james.newtonking.com/archive/2008/10/16/…
R0MANARMY
15
@Brad Il a montré absolument le même code, mais en utilisant un modèle
Mia
L'idée n'est donc que le formatage
Indenté
Cette méthode permet également d'éviter de faire des erreurs de format JSON.
Anshuman Goel
173

Un exemple de code plus court pour la bibliothèque Json.Net

private static string FormatJson(string json)
{
    dynamic parsedJson = JsonConvert.DeserializeObject(json);
    return JsonConvert.SerializeObject(parsedJson, Formatting.Indented);
}
dvdmn
la source
1
Vous pouvez réellement aller plus loin et créer une méthode d'extension; rendez-le public et changez la signature en FormatJson (cette chaîne json)
bdwakefield
129

Si vous avez une chaîne JSON et que vous voulez la "raffiner", mais que vous ne voulez pas la sérialiser vers et depuis un type C # connu, alors ce qui suit fait l'affaire (en utilisant JSON.NET):

using System;
using System.IO;
using Newtonsoft.Json;

class JsonUtil
{
    public static string JsonPrettify(string json)
    {
        using (var stringReader = new StringReader(json))
        using (var stringWriter = new StringWriter())
        {
            var jsonReader = new JsonTextReader(stringReader);
            var jsonWriter = new JsonTextWriter(stringWriter) { Formatting = Formatting.Indented };
            jsonWriter.WriteToken(jsonReader);
            return stringWriter.ToString();
        }
    }
}
Duncan Smart
la source
6
Pour seulement embellir une chaîne Json, c'est une solution bien plus appropriée que les autres ...
Jens Marchewka
2
Les cas d'utilisation suivants échoueront: JsonPrettify("null")etJsonPrettify("\"string\"")
Ekevoo
1
Merci @Ekevoo, je l'ai ramené à ma version précédente!
Duncan Smart
@DuncanSmart J'adore ça! Cette version crée beaucoup moins d'objets temporaires. Je pense que c'est mieux que celui que j'ai critiqué même si ces cas d'utilisation fonctionnaient.
Ekevoo
97

Version la plus courte pour embellir le JSON existant: (modifier: en utilisant JSON.net)

JToken.Parse("mystring").ToString()

Contribution:

{"menu": { "id": "file", "value": "File", "popup": { "menuitem": [ {"value": "New", "onclick": "CreateNewDoc()"}, {"value": "Open", "onclick": "OpenDoc()"}, {"value": "Close", "onclick": "CloseDoc()"} ] } }}

Production:

{
  "menu": {
    "id": "file",
    "value": "File",
    "popup": {
      "menuitem": [
        {
          "value": "New",
          "onclick": "CreateNewDoc()"
        },
        {
          "value": "Open",
          "onclick": "OpenDoc()"
        },
        {
          "value": "Close",
          "onclick": "CloseDoc()"
        }
      ]
    }
  }
}

Pour imprimer joliment un objet:

JToken.FromObject(myObject).ToString()
asherber
la source
4
Cela fonctionne même sans connaître à l'avance la structure du json. Et c'est la réponse la plus courte ici。
foresightyj
1
Cela fonctionne, mais uniquement si l'objet json n'est pas un tableau. Si vous savez que ce sera un tableau, vous pouvez nous utiliser JArray.Parse à la place.
Luke Z
3
Ah, bon point, merci. J'ai mis à jour ma réponse pour utiliser à la JTokenplace de JObject. Cela fonctionne avec des objets ou des tableaux, puisque JTokenc'est la classe ancêtre pour les deux JObjectet JArray.
asherber
Merci beaucoup, mec, j'ai perdu environ 2 heures pour arriver à cette solution ... Je ne peux pas imaginer ma vie sans @stackoverflow ...
Rudresha Parameshappa
Je préfère vraiment celle-ci aux autres réponses. Code court et efficace. Merci
Marc Roussel
47

Oneliner utilisant Newtonsoft.Json.Linq:

string prettyJson = JToken.Parse(uglyJsonString).ToString(Formatting.Indented);
Dariusz
la source
Je suis d'accord qu'il s'agit de l'API la plus simple pour formater JSON à l'aide de Newtonsoft
Ethan Wu
2
Impossible de trouver cela dans Newtonsoft.Json ... j'ai peut-être une version plus ancienne.
cslotty
2
Il se trouve dans l'espace de noms NewtonSoft.Json.Linq. Je ne le sais que parce que je suis allé le chercher aussi.
Captain Kenpachi
12

Vous pouvez utiliser la méthode standard suivante pour obtenir Json formaté

JsonReaderWriterFactory.CreateJsonWriter (Stream stream, Encoding encoding, bool ownsStream, bool indent, string indentChars)

Définissez uniquement "indent == true"

Essayez quelque chose comme ça

    public readonly DataContractJsonSerializerSettings Settings = 
            new DataContractJsonSerializerSettings
            { UseSimpleDictionaryFormat = true };

    public void Keep<TValue>(TValue item, string path)
    {
        try
        {
            using (var stream = File.Open(path, FileMode.Create))
            {
                //var currentCulture = Thread.CurrentThread.CurrentCulture;
                //Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;

                try
                {
                    using (var writer = JsonReaderWriterFactory.CreateJsonWriter(
                        stream, Encoding.UTF8, true, true, "  "))
                    {
                        var serializer = new DataContractJsonSerializer(type, Settings);
                        serializer.WriteObject(writer, item);
                        writer.Flush();
                    }
                }
                catch (Exception exception)
                {
                    Debug.WriteLine(exception.ToString());
                }
                finally
                {
                    //Thread.CurrentThread.CurrentCulture = currentCulture;
                }
            }
        }
        catch (Exception exception)
        {
            Debug.WriteLine(exception.ToString());
        }
    }

Faites attention aux lignes

    var currentCulture = Thread.CurrentThread.CurrentCulture;
    Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
    ....
    Thread.CurrentThread.CurrentCulture = currentCulture;

Pour certains types de sérialiseurs xml, vous devez utiliser InvariantCulture pour éviter les exceptions pendant la désérialisation sur les ordinateurs avec différents paramètres régionaux. Par exemple, un format non valide de double ou DateTime les provoque parfois.

Pour désérialiser

    public TValue Revive<TValue>(string path, params object[] constructorArgs)
    {
        try
        {
            using (var stream = File.OpenRead(path))
            {
                //var currentCulture = Thread.CurrentThread.CurrentCulture;
                //Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;

                try
                {
                    var serializer = new DataContractJsonSerializer(type, Settings);
                    var item = (TValue) serializer.ReadObject(stream);
                    if (Equals(item, null)) throw new Exception();
                    return item;
                }
                catch (Exception exception)
                {
                    Debug.WriteLine(exception.ToString());
                    return (TValue) Activator.CreateInstance(type, constructorArgs);
                }
                finally
                {
                    //Thread.CurrentThread.CurrentCulture = currentCulture;
                }
            }
        }
        catch
        {
            return (TValue) Activator.CreateInstance(typeof (TValue), constructorArgs);
        }
    }

Merci!

Makeman
la source
Bonjour, @Makeman, avez-vous déjà reproduit des erreurs de sérialisation causées par différentes cultures? On dirait que les conversions XmlJsonWriter / Reader sont toutes invariantes à la culture.
Olexander Ivanitskyi
Bonjour, je ne suis pas sûr de XmlJsonWriter / Reader, mais DataContractJsonSerializer utilise Thread.CurrentThread.CurrentCulture. Des erreurs peuvent se produire lorsque les données ont été sérialisées sur la machine A mais désérialisées sur le B avec d'autres paramètres régionaux.
Makeman
J'ai décompilé DataContractJsonSerializeren assemblage System.Runtime.Serialization v.4.0.0.0, il n'y a pas d'utilisation explicite de CurrentCulture. La seule utilisation d'une culture est CultureInfo.InvariantCulturedans la classe de base XmlObjectSerializer, méthode interne TryAddLineInfo.
Olexander Ivanitskyi
Alors, c'est peut-être mon erreur. Je le vérifierai plus tard. Possible, j'extrapole ce problème de culture à partir de l'implémentation d'un autre sérialiseur.
Makeman
1
J'ai modifié la réponse originale. Il semble que les sérialiseurs DataContract soient indépendants de la culture, mais vous devez faire attention pour éviter les erreurs spécifiques à la culture lors de la sérialisation par d'autres types de sérialiseurs. :)
Makeman
6

Tout cela peut se faire en une seule ligne:

string jsonString = JsonConvert.SerializeObject(yourObject, Formatting.Indented);
Ebube
la source
1
N'oubliez pas d'ajouter 'using Newtonsoft.Json'
Ebube
mieux répondre à mon ami.
RogerEdward
5

Voici une solution utilisant la bibliothèque System.Text.Json de Microsoft :

static string FormatJsonText(string jsonString)
{
    using var doc = JsonDocument.Parse(
        jsonString,
        new JsonDocumentOptions
        {
            AllowTrailingCommas = true
        }
    );
    MemoryStream memoryStream = new MemoryStream();
    using (
        var utf8JsonWriter = new Utf8JsonWriter(
            memoryStream,
            new JsonWriterOptions
            {
                Indented = true
            }
        )
    )
    {
        doc.WriteTo(utf8JsonWriter);
    }
    return new System.Text.UTF8Encoding()
        .GetString(memoryStream.ToArray());
}
Andrew Shepherd
la source
C'est une bonne solution pour ceux qui ne peuvent pas acheter un package supplémentaire. Fonctionne bien.
Mark T
2

J'ai d'abord voulu ajouter un commentaire sous Duncan Smart Post, mais malheureusement je n'ai pas encore assez de réputation pour laisser des commentaires. Je vais donc l'essayer ici.

Je veux juste mettre en garde contre les effets secondaires.

JsonTextReader analyse en interne json en JTokens typés puis les sérialise.

Par exemple, si votre JSON d'origine était

 { "double":0.00002, "date":"\/Date(1198908717056)\/"}

Après avoir joliment vous obtenez

{ 
    "double":2E-05,
    "date": "2007-12-29T06:11:57.056Z"
}

Bien sûr, les deux chaînes json sont équivalentes et se désérialisent en objets structurellement égaux, mais si vous devez conserver les valeurs de chaîne d'origine, vous devez prendre cela en considération.

Max Venediktov
la source
Il y a une grande discussion sur ce détail ici ... github.com/JamesNK/Newtonsoft.Json/issues/862 Intéressant de voir comment ce détail a évolué. J'ai appris quelque chose de nouveau sur mon analyseur json principal - Merci pour votre commentaire.
Sql Surfer
2

Utilisation de l' System.Text.Jsonensemble JsonSerializerOptions.WriteIndented = true:

JsonSerializerOptions options = new JsonSerializerOptions { WriteIndented = true };
string json = JsonSerializer.Serialize<Type>(object, options);
Jamie Kitson
la source
2

netcoreapp3.1

var js = JsonSerializer.Serialize(obj, new JsonSerializerOptions {
             WriteIndented = true
         });
Harveyt
la source
0

Cela a fonctionné pour moi. Dans le cas où quelqu'un cherche une version VB.NET.

@imports System
@imports System.IO
@imports Newtonsoft.Json

Public Shared Function JsonPrettify(ByVal json As String) As String
  Using stringReader = New StringReader(json)

    Using stringWriter = New StringWriter()
      Dim jsonReader = New JsonTextReader(stringReader)
      Dim jsonWriter = New JsonTextWriter(stringWriter) With {
          .Formatting = Formatting.Indented
      }
      jsonWriter.WriteToken(jsonReader)
      Return stringWriter.ToString()
    End Using
  End Using
End Function
Deedz
la source
0

Le code ci-dessous fonctionne pour moi:

JsonConvert.SerializeObject(JToken.Parse(yourobj.ToString()))
nouvel utilisateur
la source