Deserializar JSON con C #

206

Estoy tratando de deserializar la llamada Graph API de un amigo de Facebook en una lista de objetos. El objeto JSON se ve así:

{"data":[{"id":"518523721","name":"ftyft"},
         {"id":"527032438","name":"ftyftyf"},
         {"id":"527572047","name":"ftgft"},
         {"id":"531141884","name":"ftftft"},
         {"id":"532652067","name"...

List<EFacebook> facebooks = new JavaScriptSerializer().Deserialize<List<EFacebook>>(result);

No funciona porque el objeto primitivo no es válido. ¿Cómo puedo deserializar esto?

Peter Mortensen
fuente
3
escribir una deserializer personalizada específicamente para atender a tales JSON ...
ashutosh Raina
2
o puede usar un Dictionary<string,string>, consulte: stackoverflow.com/questions/7699972/…
Kakashi
9
Tu amigo: json2csharp.com
nawfal
44
En realidad, los estudios visuales (a partir de 2013 o 2012 con herramientas web instaladas) tienen esta funcionalidad exacta incorporada: Edición> Pegado especial> Pegar JSON como clases
floomby

Respuestas:

264

Necesita crear una estructura como esta:

public class Friends
{

    public List<FacebookFriend> data {get; set;}
}

public class FacebookFriend
{

    public string id {get; set;}
    public string name {get; set;}
}

Entonces deberías poder hacer:

Friends facebookFriends = new JavaScriptSerializer().Deserialize<Friends>(result);

Los nombres de mis clases son solo un ejemplo. Debes usar nombres propios.

Agregar una prueba de muestra:

string json =
    @"{""data"":[{""id"":""518523721"",""name"":""ftyft""}, {""id"":""527032438"",""name"":""ftyftyf""}, {""id"":""527572047"",""name"":""ftgft""}, {""id"":""531141884"",""name"":""ftftft""}]}";

Friends facebookFriends = new System.Web.Script.Serialization.JavaScriptSerializer().Deserialize<Friends>(json);

foreach(var item in facebookFriends.data)
{
    Console.WriteLine("id: {0}, name: {1}", item.id, item.name);
}

Produce:

id: 518523721, name: ftyft
id: 527032438, name: ftyftyf
id: 527572047, name: ftgft
id: 531141884, name: ftftft
Ícaro
fuente
3
Sí, es lo que no quiero hacer, crear un nuevo objeto para sostener a los niños. Creo que voy a substraer el json sacando el objeto primitivo. Gracias.
@ Kevin Holditch gracias por la corrección. Me perdí un poco importante :)
Icarus
2
Lo que no me gusta de este System.Web.Script.Serialization.JavaScriptSerializer () es que siempre necesita un tipo T definido. En Java existe esta biblioteca (paquete) org.java que permanece totalmente anónima: "JSONObject [" param "]. JSONarray (5)" etc
deportes
2
Es importante tener en cuenta que los establecedores para las propiedades de identificación y nombre deben dejarse públicos. Si están configurados como privados o protegidos, la deserialización se ejecutará sin error pero todos los datos serán nulos.
Isaac Zais
2
@sports, puede hacerlo en C # deserializando a una dinámica, pero el rendimiento es mucho mejor si deserializa a un tipo conocido.
PRMan
50

A veces prefiero los objetos dinámicos:

public JsonResult GetJson()
{
  string res;
  WebClient client = new WebClient();

  // Download string
  string value = client.DownloadString("https://api.instagram.com/v1/users/000000000/media/recent/?client_id=clientId");

  // Write values
  res = value;
  dynamic dyn = JsonConvert.DeserializeObject(res);
  var lstInstagramObjects = new List<InstagramModel>();

  foreach(var obj in dyn.data)
  {
    lstInstagramObjects.Add(new InstagramModel()
    {
      Link = (obj.link != null) ? obj.link.ToString() : "",
      VideoUrl = (obj.videos != null) ? obj.videos.standard_resolution.url.ToString() : "",
      CommentsCount = int.Parse(obj.comments.count.ToString()),
      LikesCount = int.Parse(obj.likes.count.ToString()),
      CreatedTime = new System.DateTime(1970, 1, 1, 0, 0, 0, 0).AddSeconds((double.Parse(obj.created_time.ToString()))),
      ImageUrl = (obj.images != null) ? obj.images.standard_resolution.url.ToString() : "",
      User = new InstagramModel.UserAccount()
             {
               username = obj.user.username,
               website = obj.user.website,
               profile_picture = obj.user.profile_picture,
               full_name = obj.user.full_name,
               bio = obj.user.bio,
               id = obj.user.id
             }
    });
  }

  return Json(lstInstagramObjects, JsonRequestBehavior.AllowGet);
}
Bishoy Hanna
fuente
Un ejemplo de una instancia en la que esto fue útil fue cuando el objeto que estaba tratando de deserializar contenía una propiedad que era una interfaz
soupy1976
2
Una explicación estaría en orden.
Peter Mortensen el
¿Por qué preferirías esto sobre la respuesta aceptada por @Icarus?
Cuestionando el
@Preguntar, deserializar a clases de tipos fuertes descuidaría cualquier propiedad que no estuviera en sus clases, mientras que deserializar a objetos dinámicos simplemente devolvería un objeto .Net dinámico que es flexible a cualquier propiedad nueva creada en el futuro sin el requisito de actualizar sus clases. (como dije, a veces no es estándar)
Bishoy Hanna
39

Una excelente manera de generar automáticamente estas clases para usted es copiar su salida JSON y lanzarla aquí:

http://json2csharp.com/

Le proporcionará un punto de partida para retocar sus clases para la deserialización.

Jack Fairfield
fuente
28

Muy fácilmente podemos analizar el contenido JSON con la ayuda del diccionario y JavaScriptSerializer. Aquí está el código de muestra mediante el cual analizo el contenido JSON de un archivo ashx.

var jss = new JavaScriptSerializer();
string json = new StreamReader(context.Request.InputStream).ReadToEnd();
Dictionary<string, string> sData = jss.Deserialize<Dictionary<string, string>>(json);
string _Name = sData["Name"].ToString();
string _Subject = sData["Subject"].ToString();
string _Email = sData["Email"].ToString();
string _Details = sData["Details"].ToString();
Thomas
fuente
3
Esta solución es muy útil si no tiene el tiempo o la necesidad de crear contratos de datos. Especialmente si está interesado en solo unos pocos atributos enterrados en la estructura JSON. En esa situación, puede usar una serie de declaraciones para navegar a lo que necesita. Nota: el tipo para deserializar también podría ser uno de los siguientes: Diccionario <cadena, objeto> o ArrayList (cuando un nodo tiene una estructura repetitiva).
Philippe Monnet
1
Obtengo una excepción de tiempo de ejecución con esto: no hay un constructor sin parámetros definido para el tipo de 'System.String' en la línea de código Deserialize.
RSK
20

Newtonsoft.JSONEs una buena solución para este tipo de situaciones. También Newtonsof.JSONes más rápido que otros, como JavaScriptSerializer, DataContractJsonSerializer.

En esta muestra, puede hacer lo siguiente:

var jsonData = JObject.Parse("your JSON data here");

Luego puede enviar jsonData a JArray, y puede usar un forbucle para obtener datos en cada iteración.

Además, quiero agregar algo:

for (int i = 0; (JArray)jsonData["data"].Count; i++)
{
    var data = jsonData[i - 1];
}

Trabajar con objetos dinámicos y usar Newtonsoft serialize es una buena opción.

OnurBulbul
fuente
15

Estoy de acuerdo con Icarus (habría comentado si pudiera), pero en lugar de usar una clase CustomObject , usaría un Diccionario (en caso de que Facebook agregue algo).

private class MyFacebookClass
{
    public IList<IDictionary<string, string>> data { get; set; }
}

o

private class MyFacebookClass
{
    public IList<IDictionary<string, object>> data { get; set; }
}
Stijn Bollen
fuente
3
El uso dinámico funciona mejor en las nuevas versiones. public IList<IDictionary<string, dynmaic>> data { get; set; }
BJury
3

Publicación por entregas:

// Convert an object to JSON string format
string jsonData = JsonConvert.SerializeObject(obj);

Response.Write(jsonData);

Deserialización :

Para deserializar un objeto dinámico

  string json = @"{
      'Name': 'name',
      'Description': 'des'
    }";

var res = JsonConvert.DeserializeObject< dynamic>(json);

Response.Write(res.Name);
ravula sandeep
fuente
3

Puedes usar estas 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
1

Aquí hay otro sitio que lo ayudará con todo el código que necesita siempre que tenga disponible una cadena JSON formateada correctamente:

https://app.quicktype.io/

Liknes
fuente
1

Si usa .NET Core 3.0, puede usar System.Text.Json (que ahora está incorporado) para deserializar JSON.

El primer paso es crear clases para modelar el JSON. Hay muchas herramientas que pueden ayudar con esto, y algunas de las respuestas aquí las enumeran.

Algunas opciones son http://json2csharp.com , http://app.quicktype.io , o use Visual Studio (menú EditarPegado especialPegar JSON como clases ).

public class Person
{
    public string Id { get; set; }
    public string Name { get; set; }
}

public class Response
{
    public List<Person> Data { get; set; }
}

Entonces puedes deserializar usando:

var people = JsonSerializer.Deserialize<Response>(json);

Si necesita agregar configuraciones, como el camelCasemanejo, pase la configuración del serializador al deserializador de esta manera:

var options = new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
var person = JsonSerializer.Deserialize<Response>(json, options);
haldo
fuente