Como obtenho JSON formatado no .NET usando C #?


256

Estou usando o analisador .NET JSON e gostaria de serializar meu arquivo de configuração para que fique legível. Então, em vez de:

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

Eu gostaria de algo mais agradável como:

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

Meu código é algo como isto:

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

Respostas:


257

Você terá dificuldade em fazer isso com o JavaScriptSerializer.

Experimente o JSON.Net .

Com pequenas modificações do exemplo 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; }
    }
}

Resultados

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

Documentação: serializar um objeto


Há também um exemplo de formatação de saída JSON em seu blog james.newtonking.com/archive/2008/10/16/...
R0MANARMY

15
@Brad Ele mostrou absolutamente o mesmo código, mas usando um modelo
Mia

Então, a idéia é apenas Formatting.Indented
FindOutIslamNow

Este método também evita que você cometa erros de formato JSON.
Anshuman Goel

173

Um código de amostra mais curto para a biblioteca Json.Net

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

1
Você pode realmente dar um passo adiante e criar um método de extensão; torne-o público e altere a assinatura para FormatJson (esta string json)
bdwakefield

129

Se você possui uma cadeia de caracteres JSON e deseja "prettificá-la", mas não deseja serializá-la de e para um tipo C # conhecido, o seguinte é o seguinte (usando 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
Por apenas embelezar uma string JSON esta é uma solução muito mais adequada do que os outros ...
Jens Marchewka

2
Os seguintes casos de uso falharão: JsonPrettify("null")eJsonPrettify("\"string\"")
Ekevoo 26/07

1
Obrigado @Ekevoo, eu revirei para a minha versão anterior!
Duncan Inteligente

@DuncanSmart I love this! Essa versão cria muito menos objetos temporários. Eu acho que é melhor do que o que eu critiquei, mesmo que esses casos de uso funcionassem.
Ekevoo

97

Versão mais curta para pretextar o JSON existente: (editar: usando JSON.net)

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

Entrada:

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

Resultado:

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

Para imprimir bonito um objeto:

JToken.FromObject(myObject).ToString()

4
Isso funciona mesmo sem conhecer a estrutura do json antecipadamente. E é a resposta mais curta aqui #
foresightyj

1
Isso funciona, mas apenas se o objeto json não for uma matriz. Se você sabe que será uma matriz, você pode usar o JArray.Parse.
Luke Z

3
Ah, bom ponto, obrigado. Atualizei minha resposta para usar em JTokenvez de JObject. Isso funciona com objetos ou matrizes, já que JTokené a classe ancestral de ambos JObjecte JArray.
asherber

Muito obrigado, homem que eu desperdiçados cerca de 2 horas para chegar a esta solução ... Não posso imaginar minha vida sem @stackoverflow ...
Rudresha Parameshappa

Eu realmente prefiro este sobre as outras respostas. Código curto e eficaz. Obrigado
Marc Roussel 29/11

47

Oneliner usando Newtonsoft.Json.Linq:

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

Eu concordo que isso é a API mais simples para formatação JSON usando Newtonsoft
Ethan Wu

2
Não foi possível encontrar isso no Newtonsoft.Json ... talvez eu tenha uma versão mais antiga.
#

2
Está no espaço para nome NewtonSoft.Json.Linq. Só sei disso porque fui procurar também.
Capitão Kenpachi,

12

Você pode usar o seguinte método padrão para obter o formato Json

JsonReaderWriterFactory.CreateJsonWriter (Fluxo de fluxo, codificação de codificação, bool ownsStream, indent bool, string indentChars)

Defina apenas "indent == true"

Tente algo como isto

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

Preste atenção nas linhas

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

Para alguns tipos de serializadores xml, você deve usar InvariantCulture para evitar exceções durante a desserialização nos computadores com configurações regionais diferentes. Por exemplo, o formato inválido de double ou DateTime às vezes os causa.

Para desserialização

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

Obrigado!


Oi, @Makeman, você já reproduziu erros de serialização causados ​​por diferentes culturas? Parece que as conversões XmlJsonWriter / Reader são todas invariantes à cultura.
Olexander Ivanitskyi

Olá, não tenho certeza sobre o XmlJsonWriter / Reader, mas o DataContractJsonSerializer usa Thread.CurrentThread.CurrentCulture. Podem ocorrer erros quando os dados foram serializados na máquina A, mas desserializados no B com outras configurações regionais.
Makeman

Eu descompilei DataContractJsonSerializerna montagem System.Runtime.Serialization v.4.0.0.0, não há uso explícito de CurrentCulture. O único uso de uma cultura é CultureInfo.InvariantCulturena classe base XmlObjectSerializer, método interno TryAddLineInfo.
Olexander Ivanitskyi

Então, talvez seja o meu erro. Vou verificar mais tarde. Possível, estou extrapolando esse problema de cultura da implementação de outro serializador.
Makeman

1
Eu editei a resposta original. Parece que os serializadores DataContract são independentes da cultura, mas você deve prestar atenção para evitar erros específicos da cultura durante a serialização por outros tipos de serializadores. :)
Makeman 14/10/19

6

Tudo isso pode ser feito em uma linha simples:

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

1
Lembre-se de adicionar 'using Newtonsoft.Json'
Ebube 18/03

melhor responder meu amigo.
RogerEdward

5

Aqui está uma solução usando a biblioteca System.Text.Json da 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());
}

Esta é uma boa solução para quem não pode comprar um pacote adicional. Funciona bem.
Mark T

2

Primeiro, eu queria adicionar um comentário no post de Duncan Smart, mas infelizmente ainda não tenho reputação suficiente para deixar comentários. Então, eu vou tentar aqui.

Eu só quero avisar sobre efeitos colaterais.

O JsonTextReader analisa internamente o json nos JTokens digitados e os serializa de volta.

Por exemplo, se o seu JSON original foi

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

Depois de fingir que você começa

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

É claro que ambas as strings json são equivalentes e desserializam para objetos estruturalmente iguais, mas se você precisar preservar os valores originais das strings, precisará levar isso em consideração


Há uma grande discussão sobre esse detalhe aqui ... github.com/JamesNK/Newtonsoft.Json/issues/862 Interessante como esse detalhe evoluiu. Aprendi algo novo sobre meu analisador json primário - Obrigado pelo seu comentário.
Sql Surfer

2

Usando o System.Text.Jsonconjunto 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

Isso funcionou para mim. Caso alguém esteja procurando uma versão do 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

O código abaixo funciona para mim:

JsonConvert.SerializeObject(JToken.Parse(yourobj.ToString()))
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.