¿Cómo obtengo formato JSON en .NET usando C #?

256

Estoy usando el analizador .NET JSON y me gustaría serializar mi archivo de configuración para que sea legible. Entonces en lugar de:

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

Me gustaría algo más agradable como:

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

Mi código es algo como esto:

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
fuente

Respuestas:

257

Va a tener dificultades para lograr esto con JavaScriptSerializer.

Prueba JSON.Net .

Con modificaciones menores del ejemplo de 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"
}

Documentación: serializar un objeto

Sanders del cielo
fuente
También hay un ejemplo de formato de salida json en su blog james.newtonking.com/archive/2008/10/16/…
R0MANARMY
15
@Brad Mostró absolutamente el mismo código, pero usando un modelo
Mia
Entonces, la idea es solo formatear
hecho
Este método también evita que uno cometa errores de formato JSON.
Anshuman Goel
173

Un código de muestra más corto para la biblioteca Json.Net

private static string FormatJson(string json)
{
    dynamic parsedJson = JsonConvert.DeserializeObject(json);
    return JsonConvert.SerializeObject(parsedJson, Formatting.Indented);
}
dvdmn
fuente
1
De hecho, puede llevar esto un paso más allá y crear un método de extensión; hacerlo público y cambiar la firma a FormatJson (esta cadena json)
bdwakefield
129

Si tiene una cadena JSON y quiere "prettificarla", pero no quiere serializarla hacia y desde un tipo C # conocido, entonces lo siguiente hace el truco (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
fuente
66
Solo para embellecer una cadena Json, esta es una solución mucho más adecuada que las demás ...
Jens Marchewka
2
Los siguientes casos de uso fallarán: JsonPrettify("null")yJsonPrettify("\"string\"")
Ekevoo
1
¡Gracias @Ekevoo, lo he regresado a mi versión anterior!
Duncan Smart
@DuncanSmart ¡Me encanta esto! Esa versión crea mucho menos objetos temporales. Creo que es mejor que el que critiqué incluso si esos casos de uso funcionaran.
Ekevoo
97

Versión más corta para embellecer 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()"} ] } }}

Salida:

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

Para imprimir un objeto bonito:

JToken.FromObject(myObject).ToString()
asherber
fuente
44
Esto funciona incluso sin conocer de antemano la estructura del json. Y es la respuesta más corta aquí。
prospectightyj
1
Esto funciona, pero solo si el objeto json no es una matriz. Si sabe que será una matriz, puede usar JArray.Parse en su lugar.
Luke Z
3
Ah, buen punto, gracias. He actualizado mi respuesta para usar en JTokenlugar de JObject. Esto funciona con objetos o matrices, ya que JTokenes la clase ancestro para ambos JObjecty JArray.
asherber
Muchas gracias, hombre que perdí alrededor de 2 horas para llegar a esta solución ... No puedo imaginar mi vida sin @stackoverflow ...
Rudresha Parameshappa
Realmente prefiero esta sobre las otras respuestas. Código corto y efectivo. Gracias
Marc Roussel
47

Oneliner usando Newtonsoft.Json.Linq:

string prettyJson = JToken.Parse(uglyJsonString).ToString(Formatting.Indented);
Dariusz
fuente
Estoy de acuerdo en que esta es la API más simple para formatear JSON usando Newtonsoft
Ethan Wu
2
No pude encontrar esto en Newtonsoft.Json ... tal vez tengo una versión anterior.
cslotty 01 de
2
Está en el espacio de nombres NewtonSoft.Json.Linq. Solo sé esto porque fui a buscarlo también.
Capitán Kenpachi el
12

Puede usar el siguiente método estándar para formatear Json

JsonReaderWriterFactory.CreateJsonWriter (Stream stream, codificación de codificación, bool poseeStream, bool indent, string indentChars)

Solo establezca "sangría == verdadero"

Intenta algo como esto

    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 atención a las líneas.

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

Para algunos tipos de serializadores xml, debe usar InvariantCulture para evitar excepciones durante la deserialización en las computadoras con diferentes configuraciones regionales. Por ejemplo, formato no válido de double o DateTime veces los causa.

Para deserializar

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

¡Gracias!

Makeman
fuente
Hola, @Makeman, ¿alguna vez has reproducido errores de serialización causados ​​por diferentes culturas? Parece que las conversiones XmlJsonWriter / Reader son invariables en todas las culturas.
Olexander Ivanitskyi
Hola, no estoy seguro acerca de XmlJsonWriter / Reader, pero DataContractJsonSerializer usa Thread.CurrentThread.CurrentCulture. Pueden producirse errores cuando los datos se han serializado en la máquina A pero se han deserializado en la B con otra configuración regional.
Makeman
Descompilé DataContractJsonSerializeren ensamblado System.Runtime.Serialization v.4.0.0.0, no hay un uso explícito de CurrentCulture. El único uso de una cultura es CultureInfo.InvariantCultureen la clase base XmlObjectSerializer, método interno TryAddLineInfo.
Olexander Ivanitskyi
Entonces, tal vez es mi error. Lo revisaré más tarde. Posiblemente, estoy extrapolando este problema cultural a partir de la implementación de otro serializador.
Makeman
1
He editado la respuesta original. Parece que los serializadores de DataContract son independientes de la cultura, pero debe prestar atención para evitar errores específicos de la cultura durante la serialización por otro tipo de serializadores. :)
Makeman
6

Todo esto se puede hacer en una línea simple:

string jsonString = JsonConvert.SerializeObject(yourObject, Formatting.Indented);
Ebube
fuente
1
Recuerde agregar 'usando Newtonsoft.Json'
Ebube
La mejor respuesta es mi amigo.
RogerEdward
5

Aquí hay una solución usando la biblioteca System.Text.Json de 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
fuente
Esta es una buena solución para aquellos que no pueden comprar un paquete adicional. Funciona bien.
Mark T
2

Primero quería agregar comentarios en la publicación Duncan Smart, pero desafortunadamente aún no tengo suficiente reputación para dejar comentarios. Así que lo intentaré aquí.

Solo quiero advertir sobre los efectos secundarios.

JsonTextReader analiza internamente json en JTokens mecanografiados y luego los serializa de nuevo.

Por ejemplo, si su JSON original era

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

Después de prettify obtienes

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

Por supuesto, ambas cadenas json son equivalentes y se deserializarán a objetos estructuralmente iguales, pero si necesita preservar los valores de cadena originales, debe tener esto en cuenta

Max Venediktov
fuente
Hay una gran discusión sobre este detalle aquí ... github.com/JamesNK/Newtonsoft.Json/issues/862 Interesante cómo ha evolucionado este detalle. Aprendí algo nuevo sobre mi analizador json primario. Gracias por tu comentario.
Sql Surfer
2

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

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

netcoreapp3.1

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

Esto funcionó para mí. En caso de que alguien esté buscando una versió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
Deedz
fuente
0

El siguiente código funciona para mí:

JsonConvert.SerializeObject(JToken.Parse(yourobj.ToString()))
Nuevo Usuario
fuente