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

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

Sky Sanders
fonte
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);
}
dvdmn
fonte
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();
        }
    }
}
Duncan Smart
fonte
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()
asherber
fonte
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);
Dariusz
fonte
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!

Makeman
fonte
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);
Ebube
fonte
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());
}
Andrew Shepherd
fonte
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

Max Venediktov
fonte
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);
Jamie Kitson
fonte
2

netcoreapp3.1

var js = JsonSerializer.Serialize(obj, new JsonSerializerOptions {
             WriteIndented = true
         });
Harveyt
fonte
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
Deedz
fonte
0

O código abaixo funciona para mim:

JsonConvert.SerializeObject(JToken.Parse(yourobj.ToString()))
novo usuário
fonte