Bagaimana cara saya mendapatkan JSON yang diformat di .NET menggunakan C #?

256

Saya menggunakan parser .NET JSON dan ingin membuat serial file config saya agar dapat dibaca. Jadi alih-alih:

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

Saya ingin sesuatu yang lebih baik seperti:

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

Kode saya kira-kira seperti ini:

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
sumber

Jawaban:

257

Anda akan mengalami kesulitan menyelesaikan ini dengan JavaScriptSerializer.

Coba JSON.Net .

Dengan sedikit modifikasi dari contoh 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; }
    }
}

Hasil

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

Dokumentasi: Buat serialisasi sebuah Objek

Sky Sanders
sumber
Ada juga contoh memformat output json di blognya james.newtonking.com/archive/2008/10/16/…
R0MANARMY
15
@Brad Dia benar-benar menunjukkan kode yang sama, tetapi menggunakan model
Mia
Jadi idenya hanyalah Pemformatan.
Diindeks
Metode ini juga menghemat satu dari membuat kesalahan format JSON.
Anshuman Goel
173

Kode sampel yang lebih pendek untuk perpustakaan Json.Net

private static string FormatJson(string json)
{
    dynamic parsedJson = JsonConvert.DeserializeObject(json);
    return JsonConvert.SerializeObject(parsedJson, Formatting.Indented);
}
dvdmn
sumber
1
Anda benar-benar dapat mengambil langkah ini lebih jauh dan membuat metode ekstensi; buat publik dan ubah tanda tangan ke FormatJson (string ini json)
bdwakefield
129

Jika Anda memiliki string JSON dan ingin "mem-prettify" itu, tetapi tidak ingin membuat cerita bersambung ke dan dari tipe C # yang dikenal, maka yang berikut melakukan trik (menggunakan 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
sumber
6
Untuk hanya mendandani senar Json, ini adalah solusi yang jauh lebih baik daripada yang lain ...
Jens Marchewka
2
JsonPrettify("null")JsonPrettify("\"string\"")
Kasing
1
Terima kasih @Ekevoo, saya telah mengembalikannya ke versi saya sebelumnya!
Duncan Smart
@DuncanSmart Saya suka ini! Versi itu menciptakan jauh lebih sedikit objek sementara. Saya pikir itu lebih baik daripada yang saya kritik bahkan jika kasus penggunaan itu berhasil.
Ekevoo
97

Versi terpendek untuk membuat cantik JSON yang ada: (edit: using JSON.net)

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

Memasukkan:

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

Keluaran:

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

Untuk mencetak objek dengan cantik:

JToken.FromObject(myObject).ToString()
asherber
sumber
4
Ini berfungsi bahkan tanpa mengetahui struktur json sebelumnya. Dan ini adalah jawaban terpendek di sini。
foresightyj
1
Ini berfungsi, tetapi hanya jika objek json bukan array. Jika Anda tahu itu akan menjadi array Anda bisa menggunakan JArray.Parse sebagai gantinya.
Luke Z
3
Ah, poin bagus, terima kasih. Saya telah memperbarui jawaban saya untuk penggunaan JTokenbukan JObject. Ini berfungsi dengan objek atau array, karena JTokenmerupakan kelas leluhur untuk keduanya JObjectdan JArray.
asherber
Terima kasih banyak, kawan saya membuang waktu sekitar 2 jam untuk mendapatkan solusi ini ... Tidak dapat membayangkan hidup saya tanpa @stackoverflow ...
Rudresha Parameshappa
Saya benar-benar lebih suka yang ini daripada jawaban yang lain. Kode pendek dan efektif. Terima kasih
Marc Roussel
47

Oneliner menggunakan Newtonsoft.Json.Linq:

string prettyJson = JToken.Parse(uglyJsonString).ToString(Formatting.Indented);
Dariusz
sumber
Saya setuju ini adalah API paling sederhana untuk memformat JSON menggunakan Newtonsoft
Ethan Wu
2
Tidak dapat menemukan ini di Newtonsoft.Json ... mungkin saya memiliki versi yang lebih lama.
cslotty
2
Ada di namespace NewtonSoft.Json.Linq. Saya hanya tahu ini karena saya juga mencarinya.
Kapten Kenpachi
12

Anda dapat menggunakan metode standar berikut untuk mendapatkan format Json

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

Hanya setel "indent == true"

Coba sesuatu seperti ini

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

Perhatikan baris Anda

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

Untuk beberapa jenis xml-serializers Anda harus menggunakan InvariantCulture untuk menghindari pengecualian selama deserialisasi pada komputer dengan pengaturan Regional yang berbeda. Misalnya, format ganda atau DateTime yang tidak valid terkadang menyebabkan mereka.

Untuk deserialisasi

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

Terima kasih!

Makeman
sumber
Hai, Pakeman, apakah Anda pernah mereproduksi kesalahan serialisasi yang disebabkan oleh budaya yang berbeda? Sepertinya konversi XmlJsonWriter / Reader semuanya budaya invarian.
Olexander Ivanitskyi
Halo, saya tidak yakin tentang XmlJsonWriter / Reader, tetapi DataContractJsonSerializer menggunakan Thread.CurrentThread.CurrentCulture. Kesalahan dapat terjadi ketika data telah diserialisasi pada mesin A tetapi deserialized pada B dengan pengaturan regional lain.
Makeman
Saya didekompilasi DataContractJsonSerializerdalam perakitan System.Runtime.Serialization v.4.0.0.0, tidak ada penggunaan eksplisit CurrentCulture. Satu-satunya penggunaan budaya adalah CultureInfo.InvariantCulturedi kelas dasar XmlObjectSerializer, metode internal TryAddLineInfo.
Olexander Ivanitskyi
Jadi, mungkin itu kesalahanku. Saya akan memeriksanya nanti. Mungkin, saya meramalkan masalah budaya ini dari implementasi serializer lain.
Makeman
1
Saya telah mengedit jawaban asli. Tampaknya serialisator DataContract bersifat independen terhadap budaya, tetapi Anda harus menyimpan perhatian untuk menghindari kesalahan spesifik budaya selama serialisasi oleh jenis serialis lain. :)
Makeman
6

Semua ini dapat dilakukan dalam satu baris sederhana:

string jsonString = JsonConvert.SerializeObject(yourObject, Formatting.Indented);
Ebube
sumber
1
Ingatlah untuk menambahkan 'menggunakan Newtonsoft.Json'
Ebube
jawab teman saya yang terbaik.
RogerEdward
5

Berikut ini adalah solusi menggunakan perpustakaan System.Text.Json 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
sumber
Ini adalah solusi yang bagus untuk mereka yang tidak dapat membeli paket tambahan. Bekerja dengan baik.
Mark T
2

Pertama saya ingin menambahkan komentar di bawah posting Duncan Smart, tapi sayangnya saya belum punya reputasi yang cukup untuk meninggalkan komentar. Jadi saya akan mencobanya di sini.

Saya hanya ingin memperingatkan tentang efek samping.

JsonTextReader secara internal mem-parsing json ke dalam JTokens yang diketik dan kemudian membuat serial kembali.

Misalnya jika JSON asli Anda

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

Setelah cantik Anda dapatkan

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

Tentu saja kedua string json adalah setara dan akan deserialize ke objek yang sama secara struktural, tetapi jika Anda perlu mempertahankan nilai string asli, Anda harus mempertimbangkan ini.

Max Venediktov
sumber
Ada diskusi hebat tentang detail ini di sini ... github.com/JamesNK/Newtonsoft.Json/issues/862 Menarik bagaimana detail ini berkembang. Saya belajar sesuatu yang baru tentang json parser utama saya - Terima kasih atas komentar Anda.
Sql Surfer
2

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

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

netcoreapp3.1

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

Ini berhasil untuk saya. Dalam kasus seseorang mencari versi 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
sumber
0

Kode di bawah ini berfungsi untuk saya:

JsonConvert.SerializeObject(JToken.Parse(yourobj.ToString()))
pengguna baru
sumber