Come posso ottenere JSON formattato in .NET usando C #?


256

Sto usando .NET JSON parser e vorrei serializzare il mio file di configurazione in modo che sia leggibile. Quindi invece di:

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

Vorrei qualcosa di più bello come:

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

Il mio codice è qualcosa del genere:

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();
}

Risposte:


257

Farai fatica a farlo con JavaScriptSerializer.

Prova JSON.Net .

Con piccole modifiche dall'esempio di 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; }
    }
}

risultati

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

Documentazione: serializzare un oggetto


C'è anche un esempio di formattazione dell'output di json sul suo blog james.newtonking.com/archive/2008/10/16/…
R0MANARMY,

15
@ Brad Ha mostrato assolutamente lo stesso codice, ma usando un modello
Mia,

Quindi l'idea è solo Formattazione.Indentata
FindOutIslamNow,

Questo metodo consente inoltre di evitare di commettere errori nel formato JSON.
Anshuman Goel,

173

Un codice di esempio più breve per la libreria Json.Net

private static string FormatJson(string json)
{
    dynamic parsedJson = JsonConvert.DeserializeObject(json);
    return JsonConvert.SerializeObject(parsedJson, Formatting.Indented);
}

1
Puoi effettivamente fare un ulteriore passo avanti e creare un metodo di estensione; rendilo pubblico e modifica la firma in FormatJson (questa stringa json)
bdwakefield il

129

Se si dispone di una stringa JSON e si desidera "prettificarla", ma non si desidera serializzarla da e verso un tipo C # noto, il trucco seguente (utilizzando 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();
        }
    }
}

6
Solo per preimpostare una stringa Json questa è una soluzione molto corretta rispetto alle altre ...
Jens Marchewka,

2
I seguenti casi d'uso falliranno: JsonPrettify("null")eJsonPrettify("\"string\"")
Ekevoo il

1
Grazie @Ekevoo, l'ho riportato alla mia versione precedente!
Duncan Smart,

@DuncanSmart Lo adoro! Quella versione crea meno oggetti temporanei. Penso che sia meglio di quello che ho criticato anche se quei casi d'uso hanno funzionato.
Ekevoo,

97

Versione più breve per preimpostare JSON esistente: (modifica: usando JSON.net)

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

Ingresso:

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

Produzione:

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

Per stampare graziosamente un oggetto:

JToken.FromObject(myObject).ToString()

4
Funziona anche senza conoscere in anticipo la struttura del json. Ed è la risposta più breve qui。
foresightyj

1
Funziona, ma solo se l'oggetto json non è un array. Se sai che sarà un array, potresti usare JArray.Parse.
Luke Z,

3
Ah, buon punto, grazie. Ho aggiornato la mia risposta da utilizzare JTokenanziché JObject. Funziona con oggetti o matrici, poiché JTokenè la classe antenata per entrambi JObjecte JArray.
asherber,

Grazie mille, amico, ho perso circa 2 ore per arrivare a questa soluzione ... Non riesco a immaginare la mia vita senza @stackoverflow ...
Rudresha Parameshappa,

Preferisco davvero questo rispetto alle altre risposte. Codice funzione ed efficace. Grazie
Marc Roussel,

47

Oneliner utilizzando Newtonsoft.Json.Linq:

string prettyJson = JToken.Parse(uglyJsonString).ToString(Formatting.Indented);

Sono d'accordo che questa è l'API più semplice per la formattazione di JSON utilizzando Newtonsoft
Ethan Wu,

2
Impossibile trovare questo in Newtonsoft.Json ... forse ho una versione precedente.
cslotty,

2
È nello spazio dei nomi NewtonSoft.Json.Linq. Lo so solo perché sono andato a cercarlo anche io.
Capitano Kenpachi,

12

È possibile utilizzare il seguente metodo standard per ottenere Json formattato

JsonReaderWriterFactory.CreateJsonWriter (stream stream, codifica codifica, bool ownsStream, bool indent, string indentChars)

Imposta solo "indent == true"

Prova qualcosa del genere

    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());
        }
    }

Presta attenzione alle linee

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

Per alcuni tipi di serializzatori xml è necessario utilizzare InvariantCulture per evitare eccezioni durante la deserializzazione sui computer con impostazioni internazionali diverse. Ad esempio, formato non valido di double o DateTime volte li causa.

Per deserializzare

    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);
        }
    }

Grazie!


Ciao @Makeman, hai mai riprodotto errori di serializzazione causati da culture diverse? Sembra che le conversioni XmlJsonWriter / Reader siano tutte invarianti di cultura.
Olexander Ivanitskyi,

Ciao, non sono sicuro di XmlJsonWriter / Reader, ma DataContractJsonSerializer utilizza Thread.CurrentThread.CurrentCulture. Si possono verificare errori quando i dati sono stati serializzati sulla macchina A ma deserializzati sulla B con altre impostazioni regionali.
Makeman

Ho decompilato DataContractJsonSerializerin assembly System.Runtime.Serialization v.4.0.0.0, non vi è alcun uso esplicito di CurrentCulture. L'unico uso di una cultura è CultureInfo.InvariantCulturenella classe base XmlObjectSerializer, metodo interno TryAddLineInfo.
Olexander Ivanitskyi,

Quindi, forse è un mio errore. Lo controllerò più tardi. Possibile, sto estrapolando questo problema di cultura dall'implementazione di un altro serializzatore.
Makeman,

1
Ho modificato la risposta originale. Sembra che i serializzatori DataContract siano indipendenti dalla cultura, ma è necessario prestare attenzione per evitare errori specifici della cultura durante la serializzazione da parte di altri tipi di serializzatori. :)
Makeman

6

Tutto ciò può essere fatto in una sola riga:

string jsonString = JsonConvert.SerializeObject(yourObject, Formatting.Indented);

1
Ricorda di aggiungere "utilizzando Newtonsoft.Json"
Ebube il

migliore risposta amico mio.
RogerEdward,

5

Ecco una soluzione che utilizza la libreria System.Text.Json di 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());
}

Questa è una buona soluzione per coloro che non possono acquistare un pacchetto aggiuntivo. Funziona bene.
Segna T

2

Prima volevo aggiungere un commento sotto Duncan Smart post, ma sfortunatamente non ho ancora abbastanza reputazione per lasciare commenti. Quindi lo proverò qui.

Voglio solo avvertire degli effetti collaterali.

JsonTextReader analizza internamente json in JTokens digitati e quindi li serializza nuovamente.

Ad esempio se il tuo JSON originale era

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

Dopo aver ricevuto Prettify

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

Naturalmente entrambe le stringhe json sono equivalenti e deserializzeranno oggetti strutturalmente uguali, ma se è necessario conservare i valori di stringa originali, è necessario tenerne conto


C'è una grande discussione su questo dettaglio qui ... github.com/JamesNK/Newtonsoft.Json/issues/862 Interessante come questo dettaglio si è evoluto. Ho imparato qualcosa di nuovo sul mio parser json primario - Grazie per il tuo commento.
Sql Surfer,

2

Utilizzando System.Text.Jsonset JsonSerializerOptions.WriteIndented = true:

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

2

netcoreapp3.1

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

0

Questo ha funzionato per me. Nel caso in cui qualcuno stia cercando una versione 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

0

Di seguito il codice funziona per me:

JsonConvert.SerializeObject(JToken.Parse(yourobj.ToString()))
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.