¿Cómo puedo analizar JSON con C #?

455

Tengo el siguiente código:

var user = (Dictionary<string, object>)serializer.DeserializeObject(responsecontent);

La entrada en responsecontentes JSON, pero no se analiza correctamente en un objeto. ¿Cómo debo deserializarlo adecuadamente?

Ola Ström
fuente
77
Hola, es posible que desee probar este enlace techblog.procurios.nl/k/n618/news/view/14605/14863/…
Vamsi
34
Hay Jsonen System.Web.Helpers, hay JsonQueryStringConverteren el System.ServiceModel.Web, no hay JavascriptSerializeren System.Web.Script.Serialization, DataContractJsonSerializeren System.Runtime.Serialization.Json, diablos, incluso MS ha decidido incluir terceros Json.NETen su API Web ASP.NET. Si pensabas que eso no era suficiente, la EM está surgiendo System.Jsonpero actualmente no es apta para el consumo. Way to go Microsoft way to go ... Elijo por el mejor espacio de nombres.
nawfal
44
@fusi el resto están en asambleas separadas. Google el nombre del espacio de nombres / clase, encontrará el ensamblaje en la documentación de msdn. Simplemente agregue referencia a ese ensamblaje.
nawfal
1
Sólo para completar, hay también JsonValueen Windows.Data.Jsonque es sólo para Windows 8 o superior. Me encanta. MS está en una misión :)
nawfal
55
NewtonSoft tiene una página de comparación en su sitio (puede ser parcial pero aún interesante): newtonsoft.com/json/help/html/jsonnetvsdotnetserializers.htm . Me gustó especialmente la fila de serialización del diccionario sin sentido :)
Ohad Schneider

Respuestas:

365

Supongo que no está utilizando Json.NET (paquete Newtonsoft.Json NuGet). Si este es el caso, entonces deberías probarlo.

Tiene las siguientes características:

  1. LINQ to JSON
  2. El JsonSerializer para convertir rápidamente sus objetos .NET a JSON y viceversa
  3. Json.NET puede producir opcionalmente JSON bien formateado y sangrado para depuración o visualización
  4. Se pueden agregar atributos como JsonIgnore y JsonProperty a una clase para personalizar cómo se serializa una clase
  5. Capacidad para convertir JSON ay desde XML
  6. Admite múltiples plataformas: .NET, Silverlight y Compact Framework

Mira el ejemplo a continuación. En este ejemplo, la JsonConvertclase se usa para convertir un objeto hacia y desde JSON. Tiene dos métodos estáticos para este propósito. Ellos son SerializeObject(Object obj)y DeserializeObject<T>(String json):

Product product = new Product();
product.Name = "Apple";
product.Expiry = new DateTime(2008, 12, 28);
product.Price = 3.99M;
product.Sizes = new string[] { "Small", "Medium", "Large" };

string json = JsonConvert.SerializeObject(product);
//{
//  "Name": "Apple",
//  "Expiry": "2008-12-28T00:00:00",
//  "Price": 3.99,
//  "Sizes": [
//    "Small",
//    "Medium",
//    "Large"
//  ]
//}

Product deserializedProduct = JsonConvert.DeserializeObject<Product>(json);
MD Sayem Ahmed
fuente
18
¿Puedo deserializar a una varvariable de tipo, en el caso de que no conozca la estructura completa de mi objetivo? Específicamente, estoy consumiendo Historias de usuarios de Rally y quiero convertirlas en objetos.
Pedro Dusso
16
@VANDERWEYENJonathan: en un navegador web moderno, JSON.parse (cadena) y JSON.stringify (objeto) manejan las fechas como cadenas ISO8601, que es el formato representado en la respuesta anterior. Es posible que desee actualizar su estándar antes de que las personas decidan que es irrelevante. Las personas necesitan fechas mucho más de lo que necesitan su estándar.
Peter Wone
3
@PeterWone: No, JSON.parse('{"Expiry": "2008-12-28T00:00:00"}').Expirydevuelve la cadena "2008-12-28T00:00:00" , no una fecha. se puede convertir en una Datevía new Date(str), pero JSON.parseno sabe nada sobre fechas. Tendría que pasar un reviver que verificara cada valor de cadena contra un patrón.
TJ Crowder
3
Dado que 3.703 segundos es lo mismo que 3s y 703ms y el separador es un punto decimal, les digo que esto es segundos a tres decimales.
Peter Wone
38
¿Por qué todo el mundo tiene ese problema con la inclusión relevantes require, include, importo usingdeclaraciones en sus respuestas. ¿Le dolería esa línea?
Tomáš Zato - Restablece a Monica el
285

Como se respondió aquí: ¿ Deserializar JSON en un objeto dinámico C #?

Es bastante simple usar Json.NET:

dynamic stuff = JsonConvert.DeserializeObject("{ 'Name': 'Jon Smith', 'Address': { 'City': 'New York', 'State': 'NY' }, 'Age': 42 }");

string name = stuff.Name;
string address = stuff.Address.City;

O usando Newtonsoft.Json.Linq:

dynamic stuff = JObject.Parse("{ 'Name': 'Jon Smith', 'Address': { 'City': 'New York', 'State': 'NY' }, 'Age': 42 }");

string name = stuff.Name;
string address = stuff.Address.City;
Dmitry Pavlov
fuente
13
@ MaxHodges, tienes razón. Acabo de utilizar "cadenas mágicas" en línea para demostrar cómo analizar los valores de cadena JSON. No quería que se viera complejo con comillas dobles escapadas. En código real, generalmente tenemos cadenas JSON obtenidas de algún lugar como variables o pasadas como parámetros.
Dmitry Pavlov
44
Sin .net 4 no tienes una palabra clave 'dinámica'. Puede usar 'var stuff' para la declaración y en lugar de 'stuff.Name' y 'stuff.Address.City' tiene 'stuff ["Name"]' y 'stuff ["Address"] ["City"]' respectivamente .
Fil
1
@Fil Eso le da un valor de tipo object, y no puede usar la indexación en un object.
Alex
138

Aquí hay algunas opciones sin usar bibliotecas de terceros:

// For that you will need to add reference to System.Runtime.Serialization
var jsonReader = JsonReaderWriterFactory.CreateJsonReader(Encoding.UTF8.GetBytes(@"{ ""Name"": ""Jon Smith"", ""Address"": { ""City"": ""New York"", ""State"": ""NY"" }, ""Age"": 42 }"), new System.Xml.XmlDictionaryReaderQuotas());

// For that you will need to add reference to System.Xml and System.Xml.Linq
var root = XElement.Load(jsonReader);
Console.WriteLine(root.XPathSelectElement("//Name").Value);
Console.WriteLine(root.XPathSelectElement("//Address/State").Value);

// For that you will need to add reference to System.Web.Helpers
dynamic json = System.Web.Helpers.Json.Decode(@"{ ""Name"": ""Jon Smith"", ""Address"": { ""City"": ""New York"", ""State"": ""NY"" }, ""Age"": 42 }");
Console.WriteLine(json.Name);
Console.WriteLine(json.Address.State);

Consulte el enlace para obtener más información sobre System.Web.Helpers.Json .

Actualización : hoy en día, la forma más fácil de obtener Web.Helperses usar el paquete NuGet .


Si no le interesan las versiones anteriores de Windows, puede usar las clases del Windows.Data.Jsonespacio de nombres:

// minimum supported version: Win 8
JsonObject root = Windows.Data.Json.JsonValue.Parse(jsonString).GetObject();
Console.WriteLine(root["Name"].GetString());
Console.WriteLine(root["Address"].GetObject()["State"].GetString());
qqbenq
fuente
¿Por qué no veo System.Web.Helpers en mi sitio web ASP.NET (4.5)? XElement, XPathSelectElement no son conocidos para mi VisualStudio. ¿Cómo educarlo?
Budda
Bueno, debe agregar referencias para las bibliotecas correspondientes (como está escrito en los comentarios anteriores), consulte este artículo para obtener más información. Además, esta pregunta puede ser de interés.
qqbenq
2
Utilicé el método Web.Helpers descrito aquí, pero me encontré con un problema que fue resuelto por esta publicación: stackoverflow.com/questions/7066726/…
Alex
1
funciona con WPF. Usando el siguiente espacio de nombres usando System.Runtime.Serialization.Json; usando System.Xml.XPath; usando System.Xml.Linq;
Shahid Neermunda
62

Si .NET 4 está disponible para usted, consulte: http://visitmix.com/writings/the-rise-of-json (archive.org)

Aquí hay un fragmento de ese sitio:

WebClient webClient = new WebClient();
dynamic result = JsonValue.Parse(webClient.DownloadString("https://api.foursquare.com/v2/users/self?oauth_token=XXXXXXX"));
Console.WriteLine(result.response.user.firstName);

Esa última consola. WriteLine es bastante dulce ...

ElonU Webdev
fuente
Lo siento, parece que las cosas han cambiado desde que respondí inicialmente. Tendré que echar un vistazo y ver qué biblioteca es la correcta ...
ElonU Webdev
77
Espero que encuentres esta biblioteca. Editar: ¿es este: dynamicjson.codeplex.com ?
user989056
1
No sé qué clase de ElonU quiso decir aquí, pero hay "JsonValue" en Windows.Data.Json (que es solo para Windows 8 y superior, extraño) y también el mismo "JsonValue" en System.Json que todavía está en vista previa y Solo Dios sabe si saldrá alguna vez. MS me confunde cuando se trata de Json.
nawfal
35

Otra solución nativa para esto, que no requiere ninguna biblioteca de terceros, sino una referencia a System.Web.Extensions es el JavaScriptSerializer. Esta no es una característica incorporada nueva pero muy desconocida desde 3.5.

using System.Web.Script.Serialization;

..

JavaScriptSerializer serializer = new JavaScriptSerializer();
objectString = serializer.Serialize(new MyObject());

y de regreso

MyObject o = serializer.Deserialize<MyObject>(objectString)
fr34kyn01535
fuente
2
Esto es muy bueno, pero necesita los componentes web, por lo que desafortunadamente no funciona en .NET 4.0 Client Profile, que es la última versión de .NET para Windows XP. La instalación completa de .NET es posible, pero muchas personas se quedan solo con Client Profile. Por el contrario, System.Runtime.Serialization.Json.DataContractJsonSerializer se admite incluso en el Perfil del cliente.
Al Kepp
3
@ fr34kyn01535: Windows XP tiene la segunda mayor cuota de mercado en computadoras de escritorio. Es relevante.
DonkeyMaster
Cuando utilicé JavaScriptSerializer para deseriarizar mi objeto, funcionó pero deserializó mi fecha incorrectamente. Debería haber sido 19/04/2018 12:00 AM pero deserializado a 18/04/2018 08:00 PM. NewtonSoft.Json.JsonConvert lo deserializó como se esperaba.
Rico
21

También puede echar un vistazo a DataContractJsonSerializer

Pieter Germishuys
fuente
1
esto es mejor ya que es compatible con .NET 3.5
Mahmoud Fayez
también es bastante más rápido que JavaScriptSerializer,
David
16

System.Json funciona ahora ...

Instale nuget https://www.nuget.org/packages/System.Json

PM> Install-Package System.Json -Version 4.5.0

Muestra :

// PM>Install-Package System.Json -Version 4.5.0

using System;
using System.Json;

namespace NetCoreTestConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            // Note that JSON keys are case sensitive, a is not same as A.

            // JSON Sample
            string jsonString = "{\"a\": 1,\"b\": \"string value\",\"c\":[{\"Value\": 1}, {\"Value\": 2,\"SubObject\":[{\"SubValue\":3}]}]}";

            // You can use the following line in a beautifier/JSON formatted for better view
            // {"a": 1,"b": "string value","c":[{"Value": 1}, {"Value": 2,"SubObject":[{"SubValue":3}]}]}

            /* Formatted jsonString for viewing purposes:
            {
               "a":1,
               "b":"string value",
               "c":[
                  {
                     "Value":1
                  },
                  {
                     "Value":2,
                     "SubObject":[
                        {
                           "SubValue":3
                        }
                     ]
                  }
               ]
            }
            */

            // Verify your JSON if you get any errors here
            JsonValue json = JsonValue.Parse(jsonString);

            // int test
            if (json.ContainsKey("a"))
            {
                int a = json["a"]; // type already set to int
                Console.WriteLine("json[\"a\"]" + " = " + a);
            }

            // string test
            if (json.ContainsKey("b"))
            {
                string b = json["b"];  // type already set to string
                Console.WriteLine("json[\"b\"]" + " = " + b);
            }

            // object array test
            if (json.ContainsKey("c") && json["c"].JsonType == JsonType.Array)
            {
                // foreach loop test
                foreach (JsonValue j in json["c"])
                {
                    Console.WriteLine("j[\"Value\"]" + " = " + j["Value"].ToString());
                }

                // multi level key test
                Console.WriteLine("json[\"c\"][0][\"Value\"]" + " = " + json["c"][0]["Value"].ToString());
                Console.WriteLine("json[\"c\"][0][\"Value\"]" + " = " + json["c"][1]["Value"].ToString());
                Console.WriteLine("json[\"c\"][1][\"SubObject\"][0][\"SubValue\"]" + " = " + json["c"][1]["SubObject"][0]["SubValue"].ToString());
            }

            Console.WriteLine();
            Console.Write("Press any key to exit.");
            Console.ReadKey();
        }
    }
}
Zunair
fuente
1
Tratar de encontrar un ejemplo de cómo usar correctamente el System.Json moderno me ha traído aquí, después de innumerables resultados para Json.NET/Newtonsoft.Json/"Newtson.Json "y las versiones anteriores de System.Json desde hace mucho tiempo en desuso. Gracias por esto.
monkey0506
1
Esto me ayudó de una manera enorme. Muchas gracias.
MAK
10

Use esta herramienta para generar una clase basada en su json:

http://json2csharp.com/

Y luego usa la clase para deserializar tu json. Ejemplo:

public class Account
{
    public string Email { get; set; }
    public bool Active { get; set; }
    public DateTime CreatedDate { get; set; }
    public IList<string> Roles { get; set; }
}


string json = @"{
  'Email': '[email protected]',
  'Active': true,
  'CreatedDate': '2013-01-20T00:00:00Z',
  'Roles': [
    'User',
    'Admin'
  ]
}";

Account account = JsonConvert.DeserializeObject<Account>(json);

Console.WriteLine(account.Email);
// [email protected]

Referencias: https://forums.asp.net/t/1992996.aspx?Nested+Json+Deserialization+to+C+object+and+using+that+object https://www.newtonsoft.com/json/help /html/DeserializeObject.htm

Bruno Pereira
fuente
9

Prueba el siguiente código:

HttpWebRequest request = (HttpWebRequest)WebRequest.Create("URL");
JArray array = new JArray();
using (var twitpicResponse = (HttpWebResponse)request.GetResponse())
using (var reader = new StreamReader(twitpicResponse.GetResponseStream()))
{
    JavaScriptSerializer js = new JavaScriptSerializer();
    var objText = reader.ReadToEnd();

    JObject joResponse = JObject.Parse(objText);
    JObject result = (JObject)joResponse["result"];
    array = (JArray)result["Detail"];
    string statu = array[0]["dlrStat"].ToString();
}
Muhammad Awais
fuente
Gracias, quería la parte ["resultado" + variable] porque quería usar variables para usar aquí, lo cual no se puede hacer fácilmente con JSON.NET.
PHPGuru
¿Esta línea está haciendo algo ... JavaScriptSerializer js = new JavaScriptSerializer (); Gracias por adelantado.
Chris Catignani
9

System.Text.Json

.NET core 3.0 viene con System.Text.Jsonincorporado, lo que significa que puede deserializar / serializar JSON sin usar una biblioteca de terceros.

Para serializar su (s) clase (s) a una cadena JSON:

var json = JsonSerializer.Serialize(order);

Para deserializar el JSON en una clase fuertemente tipada:

var order = JsonSerializer.Deserialize<Order>(json);

Entonces, si tienes una clase como la siguiente:

public class Order
{
    public int Id { get; set; }
    public string OrderNumber { get; set; }
    public decimal Balance { get; set; }
    public DateTime Opened { get; set; }
}

var json = JsonSerializer.Serialize(order);
// creates JSON ==>
{
    "id": 123456,
    "orderNumber": "ABC-123-456",
    "balance": 9876.54,
    "opened": "2019-10-21T23:47:16.85",
};

var order = JsonSerializer.Deserialize<Order>(json);
// ==> creates the above class

Una cosa a tener en cuenta es que System.Text.Json no maneja automáticamente las camelCasepropiedades JSON cuando usa su propio código (sin embargo, lo hace cuando usa las solicitudes MVC / WebAPI y el modelo de carpeta).

Para resolver esto, debe pasar JsonSerializerOptionscomo parámetro.

JsonSerializerOptions options = new JsonSerializerOptions
{        
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,  // set camelCase       
    WriteIndented = true                                // write pretty json
};

// pass options to serializer
var json = JsonSerializer.Serialize(order, options);
// pass options to deserializer
var order = JsonSerializer.Deserialize<Order>(json, options);

System.Text.Json también está disponible para .Net Framework y .Net Standard como un paquete Nu-get System.Text.Json

haldo
fuente
1
¿Qué pasa si no tienes una clase? ¿Qué pasa si solo sabes vagamente qué van a contener los datos json? ¿O si las llaves existen?
Cherona
@Cherona uso JsonDocument.Parse.
Haldo
5

Lo siguiente del sitio msdn debería, creo, ayudar a proporcionar alguna funcionalidad nativa para lo que está buscando. Tenga en cuenta que se especifica para Windows 8. Uno de estos ejemplos del sitio se enumera a continuación.

JsonValue jsonValue = JsonValue.Parse("{\"Width\": 800, \"Height\": 600, \"Title\": \"View from 15th Floor\", \"IDs\": [116, 943, 234, 38793]}");
double width = jsonValue.GetObject().GetNamedNumber("Width");
double height = jsonValue.GetObject().GetNamedNumber("Height");
string title = jsonValue.GetObject().GetNamedString("Title");
JsonArray ids = jsonValue.GetObject().GetNamedArray("IDs");

Utiliza el espacio de nombres Windows.Data.JSON .

TargetofGravity
fuente
66
Agradable, pero "Cliente mínimo admitido: Windows 8"
watbywbarif
creo que ya no es compatible y ahora hay newtonsoft json dll icouldnt find windows.data.json
virtouso
3
@virtouso, como señaló watbywbarif, en realidad es bastante nuevo, aunque el soporte mínimo de Microsoft , solo funciona en Windows 8.
TargetofGravity
4

Puedes usar las siguientes extensiones

public static class JsonExtensions
{
    public static T ToObject<T>(this string jsonText)
    {
        return JsonConvert.DeserializeObject<T>(jsonText);
    }

    public static string ToJson<T>(this T obj)
    {
        return JsonConvert.SerializeObject(obj);
    } 
}
Hidayet R. Colkusu
fuente
0

Creo que la mejor respuesta que he visto ha sido @MD_Sayem_Ahmed.

Su pregunta es "¿Cómo puedo analizar Json con C #", pero parece que desea decodificar Json. Si quieres decodificarlo, la respuesta de Ahmed es buena.

Si está tratando de lograr esto en ASP.NET Web Api, la forma más fácil es crear un objeto de transferencia de datos que contenga los datos que desea asignar:

public class MyDto{
    public string Name{get; set;}
    public string Value{get; set;}
}

Simplemente ha agregado el encabezado application / json a su solicitud (si está utilizando Fiddler, por ejemplo). Luego usaría esto en la API web de ASP.NET de la siguiente manera:

//controller method -- assuming you want to post and return data
public MyDto Post([FromBody] MyDto myDto){
   MyDto someDto = myDto;
   /*ASP.NET automatically converts the data for you into this object 
    if you post a json object as follows:
{
    "Name": "SomeName",
      "Value": "SomeValue"
}
*/
   //do some stuff
}

Esto me ayudó mucho cuando estaba trabajando en mi Web Api e hizo que mi vida fuera muy fácil.

cr1pto
fuente
0
         string json = @"{
            'Name': 'Wide Web',
            'Url': 'www.wideweb.com.br'}";

        JavaScriptSerializer jsonSerializer = new JavaScriptSerializer();
        dynamic j = jsonSerializer.Deserialize<dynamic>(json);
        string name = j["Name"].ToString();
        string url = j["Url"].ToString();
Fernando Meneses Gomes
fuente
-1
var result = controller.ActioName(objParams);
IDictionary<string, object> data = (IDictionary<string, object>)new System.Web.Routing.RouteValueDictionary(result.Data);
Assert.AreEqual("Table already exists.", data["Message"]);
Jidheesh Rajan
fuente
2
Es mejor que explique su solución en lugar de simplemente publicar una fila de código. Puedes leer ¿Cómo escribo una buena respuesta ?
Massimiliano Kraus
No olvide incluir System.Weben su proyecto referencias.
Ohad Cohen el
-3
 using (var ms = new MemoryStream(Encoding.Unicode.GetBytes(user)))
 {
    // Deserialization from JSON  
    DataContractJsonSerializer deserializer = new DataContractJsonSerializer(typeof(UserListing))
    DataContractJsonSerializer(typeof(UserListing));
    UserListing response = (UserListing)deserializer.ReadObject(ms);

 }

 public class UserListing
 {
    public List<UserList> users { get; set; }      
 }

 public class UserList
 {
    public string FirstName { get; set; }       
    public string LastName { get; set; } 
 }
Kobie Williams
fuente