¿Cómo convertir un objeto JSON en un objeto C # personalizado?

247

¿Hay una manera fácil de llenar mi objeto C # con el objeto JSON pasado a través de AJAX?

Este es el objeto JSON pasado a C # WEBMETHOD desde la página usando JSON.stringify

{
    "user": {
        "name": "asdf",
        "teamname": "b",
        "email": "c",
        "players": ["1", "2"]
    }
}

C # WebMetod que recibe el objeto JSON

[WebMethod]
public static void SaveTeam(Object user)
{

}

Clase C # que representa la estructura del objeto JSON Object pasado al WebMethod

public class User
{
    public string name { get; set; }
    public string teamname { get; set; }
    public string email { get; set; }
    public Array players { get; set; }
}
MHop
fuente
69
Me gustaría agregar que puede usar json2csharp.com para generar sus clases de C # por usted. Divulgación completa: creé este sitio.
JonathanK
Compruebe esto stackoverflow.com/questions/22191167/…
Pratik Bhoir
@JonathanK ¡Eres mi salvador!
Matheno

Respuestas:

218

Una buena forma de usar JSON en C # es con JSON.NET

Inicio rápido y documentación de API de JSON.NET: el sitio oficial lo ayuda a trabajar con él.

Un ejemplo de cómo usarlo:

public class User
{
    public User(string json)
    {
        JObject jObject = JObject.Parse(json);
        JToken jUser = jObject["user"];
        name = (string) jUser["name"];
        teamname = (string) jUser["teamname"];
        email = (string) jUser["email"];
        players = jUser["players"].ToArray();
    }

    public string name { get; set; }
    public string teamname { get; set; }
    public string email { get; set; }
    public Array players { get; set; }
}

// Use
private void Run()
{
    string json = @"{""user"":{""name"":""asdf"",""teamname"":""b"",""email"":""c"",""players"":[""1"",""2""]}}";
    User user = new User(json);

    Console.WriteLine("Name : " + user.name);
    Console.WriteLine("Teamname : " + user.teamname);
    Console.WriteLine("Email : " + user.email);
    Console.WriteLine("Players:");

    foreach (var player in user.players)
        Console.WriteLine(player);
 }
AndreyAkinshin
fuente
55
Esto funciona como un campeón, pero ¿qué pasa si tengo varios elementos en mi json y quiero hacer una lista de objetos?
Djeroen
@Djeroen: Veo dos formas de hacerlo. Si los elementos no están agrupados, intente encontrar una manera de dividir la cadena y repita el proceso en un bucle. Si están agrupados, haga un objeto de objetos
user1011138
1
Prefiero los liners mencionados en otras respuestas. En mi humilde opinión.
RayLoveless
Sí, este no es un buen enfoque, el siguiente usando DeserializeObject es mucho más limpio
Andrew
208

Como todos amamos el código de un revestimiento

Newtonsoft es más rápido que el serializador de scripts Java. ... este depende del paquete Newtonsoft NuGet, que es popular y mejor que el serializador predeterminado.

si tenemos clase, use a continuación.

Mycustomclassname oMycustomclassname = Newtonsoft.Json.JsonConvert.DeserializeObject<Mycustomclassname>(jsonString);

sin clase, entonces usa dinámico

var oMycustomclassname = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(jsonString);
MSTdev
fuente
95

Para mantener sus opciones abiertas, si está usando .NET 3.5 o posterior, aquí hay un ejemplo resumido que puede usar directamente desde el marco usando Generics. Como otros han mencionado, si no se trata solo de objetos simples, realmente debería usar JSON.net.

public static string Serialize<T>(T obj)
{
    DataContractJsonSerializer serializer = new DataContractJsonSerializer(obj.GetType());
    MemoryStream ms = new MemoryStream();
    serializer.WriteObject(ms, obj);
    string retVal = Encoding.UTF8.GetString(ms.ToArray());
    return retVal;
}

public static T Deserialize<T>(string json)
{
    T obj = Activator.CreateInstance<T>();
    MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(json));
    DataContractJsonSerializer serializer = new DataContractJsonSerializer(obj.GetType());
    obj = (T)serializer.ReadObject(ms);
    ms.Close();
    return obj;
}

Necesitarás:

using System.Runtime.Serialization;

using System.Runtime.Serialization.Json;
Jammin
fuente
@ChristianPayne ja! Buen punto, sí, estos deben estar envueltos. Mirando esto en retrospectiva, ¡solo use JSON.NET!
Jammin
2
Si la clase DataContractJsonSerializer no está visible, debe agregar una referencia a System.Runtime.Serialization haciendo clic con el botón derecho en Referencias en la solución, seleccione la pestaña .NET y seleccione System.Runtime.Serialization
DanKodi
1
Un escenario donde este se rompe. Si su objeto JSON representa propiedades con comillas simples, esta función falla. por ejemplo, no pudo analizar {'Asunto': 'Correo electrónico: Registro de actividad de usuario web11', 'EmbedAsImage': verdadero} pero pudo analizar {"Asunto": "Correo electrónico: Registro de actividad de usuario web11", "EmbedAsImage" : verdadero}
dreamerkumar
Además, necesitaba decorar mi clase simple con los atributos DataContract y DataMember. No se analizará sin él.
dreamerkumar
A diferencia de Vishal, una clase POCO funcionó perfectamente para mí ... +1 ya que esto evita una dependencia de JSON.NET.
Dunc
54

Dado su ejemplo de código, no debería necesitar hacer nada más.

Si pasa esa cadena JSON a su método web, analizará automáticamente la cadena JSON y creará un objeto Usuario rellenado como el parámetro para su método SaveTeam.

Sin embargo, en general, puede usar la JavascriptSerializerclase de la siguiente manera, o para mayor flexibilidad, use cualquiera de los diversos marcos Json que existen (Jayrock JSON es bueno) para una fácil manipulación JSON.

 JavaScriptSerializer jss= new JavaScriptSerializer();
 User user = jss.Deserialize<User>(jsonResponse); 
womp
fuente
1
Creo que debe usar un tipo innumerable (así que en este ejemplo Lista <Usuario>)
Dragouf
¿Cómo podemos deserializar si contiene un modelo de vista secundaria?
SrinivasNaidu
1
Para aquellos que buscan, debe hacer referencia al System.Web.Extensionsensamblaje y agregar un using System.Web.Script.Serializationpara llegar al JavaScriptSerializer, pero una vez que lo haga, esta parece ser la forma más limpia de deserializar sus jsoncadenas en clases concretas de c #.
Serj Sagan
41

Otra solución realmente simple es usar la biblioteca Newtonsoft.Json:

User user = JsonConvert.DeserializeObject<User>(jsonString);
Daniel
fuente
pero si el objeto Usuario tiene otros datos JSon en la propiedad, esto fallará ...
Gumuruh
@gumuruh Supongo que no entendí tu declaración. Si tiene un objeto complejo, las propiedades de la bruja son otros objetos complejos, también se convertirán, siempre que su Cadena Json tenga los datos correctamente.
Daniel
33

Los siguientes 2 ejemplos hacen uso de

  1. JavaScriptSerializer bajo System.Web.Script.Serialization O
  2. Json.Decode en System.Web.Helpers

Ejemplo 1: uso de System.Web.Script.Serialization

using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Web.Script.Serialization;

namespace Tests
{
    [TestClass]
    public class JsonTests
    {
        [TestMethod]
        public void Test()
        {
            var json = "{\"user\":{\"name\":\"asdf\",\"teamname\":\"b\",\"email\":\"c\",\"players\":[\"1\",\"2\"]}}";
            JavaScriptSerializer serializer = new JavaScriptSerializer();
            dynamic jsonObject = serializer.Deserialize<dynamic>(json);

            dynamic x = jsonObject["user"]; // result is Dictionary<string,object> user with fields name, teamname, email and players with their values
            x = jsonObject["user"]["name"]; // result is asdf
            x = jsonObject["user"]["players"]; // result is object[] players with its values
        }
    }
}

Uso: objeto JSON a objeto C # personalizado

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Web.Script.Serialization;
using System.Linq;

namespace Tests
{
    [TestClass]
    public class JsonTests
    {
        [TestMethod]
        public void TestJavaScriptSerializer()
        {
            var json = "{\"user\":{\"name\":\"asdf\",\"teamname\":\"b\",\"email\":\"c\",\"players\":[\"1\",\"2\"]}}";
            User user = new User(json);
            Console.WriteLine("Name : " + user.name);
            Console.WriteLine("Teamname : " + user.teamname);
            Console.WriteLine("Email : " + user.email);
            Console.WriteLine("Players:");
            foreach (var player in user.players)
                Console.WriteLine(player);
        }
    }

    public class User {
        public User(string json) {
            JavaScriptSerializer serializer = new JavaScriptSerializer();
            var jsonObject = serializer.Deserialize<dynamic>(json);
            name = (string)jsonObject["user"]["name"];
            teamname = (string)jsonObject["user"]["teamname"];
            email = (string)jsonObject["user"]["email"];
            players = jsonObject["user"]["players"];
        }

        public string name { get; set; }
        public string teamname { get; set; }
        public string email { get; set; }
        public Array players { get; set; }
    }
}

Ejemplo 2: uso de System.Web.Helpers

using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Web.Helpers;

namespace Tests
{
    [TestClass]
    public class JsonTests
    {
        [TestMethod]
        public void TestJsonDecode()
        {
            var json = "{\"user\":{\"name\":\"asdf\",\"teamname\":\"b\",\"email\":\"c\",\"players\":[\"1\",\"2\"]}}";
            dynamic jsonObject = Json.Decode(json);

            dynamic x = jsonObject.user; // result is dynamic json object user with fields name, teamname, email and players with their values
            x = jsonObject.user.name; // result is asdf
            x = jsonObject.user.players; // result is dynamic json array players with its values
        }
    }
}

Uso: objeto JSON a objeto C # personalizado

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Web.Helpers;
using System.Linq;

namespace Tests
{
    [TestClass]
    public class JsonTests
    {
        [TestMethod]
        public void TestJsonDecode()
        {
            var json = "{\"user\":{\"name\":\"asdf\",\"teamname\":\"b\",\"email\":\"c\",\"players\":[\"1\",\"2\"]}}";
            User user = new User(json);
            Console.WriteLine("Name : " + user.name);
            Console.WriteLine("Teamname : " + user.teamname);
            Console.WriteLine("Email : " + user.email);
            Console.WriteLine("Players:");
            foreach (var player in user.players)
                Console.WriteLine(player);
        }
    }

    public class User {
        public User(string json) {
            var jsonObject = Json.Decode(json);
            name = (string)jsonObject.user.name;
            teamname = (string)jsonObject.user.teamname;
            email = (string)jsonObject.user.email;
            players = (DynamicJsonArray) jsonObject.user.players;
        }

        public string name { get; set; }
        public string teamname { get; set; }
        public string email { get; set; }
        public Array players { get; set; }
    }
}

Este código requiere agregar el espacio de nombres System.Web.Helpers que se encuentra en,

% ProgramFiles% \ Microsoft ASP.NET \ ASP.NET Páginas web {VERSION} \ Assemblies \ System.Web.Helpers.dll

O

% ProgramFiles (x86)% \ Microsoft ASP.NET \ ASP.NET Web Pages {VERSION} \ Assemblies \ System.Web.Helpers.dll

¡Espero que esto ayude!


fuente
Esta es una muy buena respuesta, pero lo complicado es que con los dynamictipos, no obtienes ninguna verificación de tipo verdadero. Por ejemplo, si su JSON contiene "Name" : "Ahmed"y escribe incorrectamente "Nombre" en su código C #, es un error de tiempo de ejecución (bleh).
Jess
¡Gracias! Actualice la respuesta para indicar que para el Ejemplo 1, debe hacer referencia a System.Web.Extensions.dll
Valamas
1
respuesta súper genial, ¡la escritura dinámica también funciona con json.net v6.0.6!
stackuser83
7
public static class Utilities
{
    public static T Deserialize<T>(string jsonString)
    {
        using (MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(jsonString)))
        {    
            DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
            return (T)serializer.ReadObject(ms);
        }
    }
}

Más información vaya al siguiente enlace http://ishareidea.blogspot.in/2012/05/json-conversion.html

Sobre DataContractJsonSerializer Classusted puede leer aquí .

Desarrollador Syam
fuente
5

El uso de JavaScriptSerializer () es menos estricto que la solución genérica ofrecida: public static T Deserialize (string json)

Eso puede ser útil al pasar json al servidor que no coincide exactamente con la definición de Objeto a la que intenta convertir.

Ioannis Suárez
fuente
1

JSON.Net es su mejor opción, pero, dependiendo de la forma de los objetos y de si hay dependencias circulares, puede usar JavaScriptSerializer o DataContractSerializer.

Sanders del cielo
fuente
1

Serializador de JavaScript: requiere using System.Web.Script.Serialization;

public class JavaScriptSerializerDeSerializer<T>
{
    private readonly JavaScriptSerializer serializer;

    public JavaScriptSerializerDeSerializer()
    {
        this.serializer = new JavaScriptSerializer();
    }

    public string Serialize(T t)
    {
        return this.serializer.Serialize(t);
    }

    public T Deseralize(string stringObject)
    {
        return this.serializer.Deserialize<T>(stringObject);
    }
}

Serializador de contrato de datos: requiere using System.Runtime.Serialization.Json; : el tipo genérico T debería ser serializable más en contrato de datos

public class JsonSerializerDeserializer<T> where T : class
{
    private readonly DataContractJsonSerializer jsonSerializer;

    public JsonSerializerDeserializer()
    {
        this.jsonSerializer = new DataContractJsonSerializer(typeof(T));
    }

    public string Serialize(T t)
    {
        using (var memoryStream = new MemoryStream())
        {
            this.jsonSerializer.WriteObject(memoryStream, t);
            memoryStream.Position = 0;
            using (var sr = new StreamReader(memoryStream))
            {
                return sr.ReadToEnd();
            }
        }
    }

    public T Deserialize(string objectString)
    {
        using (var ms = new MemoryStream(System.Text.ASCIIEncoding.ASCII.GetBytes((objectString))))
        {
            return (T)this.jsonSerializer.ReadObject(ms);
        }
    }
}
BTE
fuente
0

En lugar de enviar como un simple objeto.

Cree una clase pública de propiedades que sea accesible y envíe los datos al método web.

[WebMethod]
public static void SaveTeam(useSomeClassHere user)
{
}

use los mismos nombres de parámetros en la llamada ajax para enviar datos.

Praveen Kumar Rejeti
fuente