Làm cách nào để có được định dạng JSON trong .NET bằng C #?


256

Tôi đang sử dụng trình phân tích cú pháp .NET JSON và muốn tuần tự hóa tệp cấu hình của mình để có thể đọc được. Vì vậy, thay vì:

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

Tôi muốn một cái gì đó đẹp hơn như:

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

Mã của tôi là một cái gì đó như thế này:

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

Câu trả lời:


257

Bạn sẽ có một thời gian khó khăn để thực hiện điều này với JavaScriptSerializer.

Hãy thử JSON.Net .

Với các sửa đổi nhỏ từ ví dụ 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; }
    }
}

Các kết quả

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

Tài liệu: Nối tiếp một đối tượng


Ngoài ra còn có một ví dụ về định dạng đầu ra json trên blog của mình james.newtonking.com/archive/2008/10/16/...
R0MANARMY

15
@Brad Anh ấy đã hiển thị hoàn toàn cùng một mã, nhưng sử dụng một mô hình
Mia

Vì vậy, ý tưởng chỉ là Định dạng
Nội dung

Phương pháp này cũng lưu một từ việc tạo ra các lỗi định dạng JSON.
Anshuman Goel

173

Mã mẫu ngắn hơn cho thư viện Json.Net

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

1
Bạn thực sự có thể tiến thêm một bước này và tạo một phương thức mở rộng; công khai và thay đổi chữ ký thành FormatJson (chuỗi này json)
bdwakefield

129

Nếu bạn có một chuỗi JSON và muốn "làm đẹp" nó, nhưng không muốn nối tiếp chuỗi đó đến và từ một loại C # đã biết thì sau đây sẽ thực hiện thủ thuật (sử dụng 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
Chỉ để làm đẹp một chuỗi Json, đây là một giải pháp phù hợp hơn các chuỗi khác ...
Jens Marchewka

2
Các trường hợp sử dụng sau đây sẽ thất bại: JsonPrettify("null")JsonPrettify("\"string\"")
Ekevoo

1
Cảm ơn @Ekevoo, tôi đã đưa nó trở lại phiên bản trước của tôi!
Duncan thông minh

@DuncanSmart Tôi thích điều này! Phiên bản đó tạo ra ít đối tượng tạm thời hơn. Tôi nghĩ rằng nó tốt hơn so với những gì tôi đã chỉ trích ngay cả khi những trường hợp sử dụng đó hoạt động.
Ekevoo

97

Phiên bản ngắn nhất để làm đẹp JSON hiện có: (chỉnh sửa: sử dụng JSON.net)

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

Đầu vào:

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

Đầu ra:

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

Để in đẹp một đối tượng:

JToken.FromObject(myObject).ToString()

4
Điều này hoạt động ngay cả khi không biết cấu trúc của json trước. Và đó là câu trả lời ngắn nhất ở đây
foresightyj

1
Điều này hoạt động, nhưng chỉ khi đối tượng json không phải là một mảng. Nếu bạn biết nó sẽ là một mảng, bạn có thể cho chúng tôi JArray.Pude thay thế.
Luke Z

3
Ah, điểm tốt, cảm ơn. Tôi đã cập nhật câu trả lời của tôi để sử dụng JTokenthay vì JObject. Điều này làm việc với các đối tượng hoặc mảng, vì JTokenlà lớp tổ tiên cho cả JObjectJArray.
Asherber

Cảm ơn rất nhiều, người đàn ông tôi đã lãng phí khoảng 2 giờ để có được giải pháp này ... Không thể tưởng tượng được cuộc sống của tôi mà không có @stackoverflow ...
Rudresha Parameshappa

Tôi thực sự thích cái này hơn các câu trả lời khác. Mã ngắn và hiệu quả. Cảm ơn bạn
Marc Roussel

47

Oneliner sử dụng Newtonsoft.Json.Linq:

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

Tôi đồng ý đây là API đơn giản nhất để định dạng JSON bằng Newtonsoft
Ethan Wu

2
Không thể tìm thấy điều này trong Newtonsoft.Json ... có lẽ tôi có phiên bản cũ hơn.
cslotty

2
Nó nằm trong không gian tên NewtonSoft.Json.Linq. Tôi chỉ biết điều này vì tôi cũng đã tìm kiếm nó.
Thuyền trưởng Kenpachi

12

Bạn có thể sử dụng phương pháp tiêu chuẩn sau để nhận được định dạng Json

JsonReaderWriterFactory.CreateJsonWriter (Luồng truyền phát, mã hóa mã hóa, bool ownStream, bool indent, chuỗi indentChars)

Chỉ đặt "thụt lề == true"

Hãy thử một cái gì đó như thế này

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

Chú ý đến các dòng

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

Đối với một số loại xml-serializer, bạn nên sử dụng InvariantCARM để tránh ngoại lệ trong quá trình khử lưu huỳnh trên các máy tính có cài đặt Vùng khác nhau. Ví dụ: định dạng kép không hợp lệ hoặc DateTime đôi khi gây ra chúng.

Để khử lưu huỳnh

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

Cảm ơn!


Xin chào, @Makeman, bạn đã bao giờ tái tạo lỗi nối tiếp do các nền văn hóa khác nhau chưa? Có vẻ như các chuyển đổi XmlJsonWriter / Reader là bất biến văn hóa.
Olexander Ivanitskyi

Xin chào, tôi không chắc chắn về XmlJsonWriter / Reader, nhưng DataContractJsonSerializer sử dụng Thread.CienThread.CiverseCocate. Lỗi có thể xảy ra khi dữ liệu đã được tuần tự hóa trên máy A nhưng được giải tuần tự hóa trên B với các cài đặt khu vực khác.
Makeman

Tôi dịch ngược DataContractJsonSerializertrong lắp ráp System.Runtime.Serialization v.4.0.0.0, không có cách sử dụng rõ ràng CurrentCulture. Cách sử dụng duy nhất của một nền văn hóa là CultureInfo.InvariantCulturetrong lớp cơ sở XmlObjectSerializer, phương thức bên trong TryAddLineInfo.
Olexander Ivanitskyi

Vì vậy, có thể đó là sai lầm của tôi. Tôi sẽ kiểm tra nó sau. Có thể, tôi ngoại suy vấn đề văn hóa này từ việc thực hiện một serializer khác.
Makeman

1
Tôi đã chỉnh sửa câu trả lời ban đầu. Có vẻ như các trình tuần tự hóa DataContract độc lập với văn hóa, nhưng bạn nên chú ý để tránh các lỗi cụ thể về văn hóa trong quá trình tuần tự hóa bởi một loại trình tuần tự hóa khác. :)
Makeman

6

Tất cả điều này có thể được thực hiện trong một dòng đơn giản:

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

1
Hãy nhớ thêm 'bằng Newtonsoft.Json'
Ebube

trả lời tốt nhất bạn của tôi
RogerEdward

5

Đây là một giải pháp sử dụng thư viện System.Text.Json của 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());
}

Đây là một giải pháp tốt cho những người không thể mua một gói bổ sung. Hoạt động tốt.
Đánh dấu

2

Đầu tiên tôi muốn thêm bình luận dưới bài đăng của Duncan Smart, nhưng tiếc là tôi chưa có đủ danh tiếng để để lại bình luận. Vì vậy, tôi sẽ thử nó ở đây.

Tôi chỉ muốn cảnh báo về tác dụng phụ.

JsonTextReader phân tích nội bộ json thành JTokens đã gõ và sau đó nối tiếp chúng trở lại.

Ví dụ: nếu JSON gốc của bạn là

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

Sau khi làm đẹp bạn nhận được

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

Tất nhiên cả hai chuỗi json đều tương đương và sẽ giải tuần tự hóa các đối tượng có cấu trúc bằng nhau, nhưng nếu bạn cần giữ nguyên các giá trị chuỗi gốc, bạn cần đưa điều này vào trong concider


Có một cuộc thảo luận tuyệt vời về chi tiết này ở đây ... github.com/JamesNK/Newtonsoft.Json/issues/862 Thú vị về cách chi tiết này đã phát triển. Tôi đã học được một cái gì đó mới về trình phân tích cú pháp json chính của tôi - Cảm ơn bạn đã nhận xét của bạn.
Sql Surfer

2

Sử dụng System.Text.Jsonbộ JsonSerializerOptions.WriteIndented = true:

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

2

netcor Ứng dụng3.1

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

0

Điều này làm việc cho tôi. Trong trường hợp ai đó đang tìm kiếm một phiên bản 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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.