Desserializar JSON com C #

206

Estou tentando desserializar a chamada da API Graph de um amigo do Facebook em uma lista de objetos. O objeto JSON se parece com:

{"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);

Não está funcionando, porque o objeto primitivo é inválido. Como posso desserializar isso?

Peter Mortensen
fonte
3
escrever uma desserializador personalizado especificamente para atender a tais json ...
ashutosh Raina
2
ou você pode usar um Dictionary<string,string>, confira: stackoverflow.com/questions/7699972/…
Kakashi
9
Seu amigo: json2csharp.com
nawfal
4
Estúdios realmente visuais (a partir de 2013 ou 2012 com ferramentas web instalados) tem esta funcionalidade exata construído em: Editar> Colar especial> Colar JSON como classes
floomby

Respostas:

264

Você precisa criar uma estrutura como esta:

public class Friends
{

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

public class FacebookFriend
{

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

Então você deve ser capaz de:

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

Os nomes das minhas aulas são apenas um exemplo. Você deve usar nomes próprios.

Adicionando um teste de amostra:

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

Produz:

id: 518523721, name: ftyft
id: 527032438, name: ftyftyf
id: 527572047, name: ftgft
id: 531141884, name: ftftft
Icaro
fonte
3
Sim, é o que eu não quero fazer, crie um novo objeto para segurar os filhos. Acho que vou substring o json tirando o objeto primitivo. Obrigado.
@ Kevin Holditch obrigado pela correção. Eu perdi um pouco importante :)
Icarus
2
O que eu não gosto neste System.Web.Script.Serialization.JavaScriptSerializer () é que você sempre precisa de um tipo definido T. Em Java, existe esta biblioteca org.java (pacote) que permanece totalmente anônima: "JSONObject [" param "]. JSONarray (5)" etc
sports
2
É importante observar que os setters para as propriedades id e name devem ser deixados públicos. Se eles estiverem configurados como privados ou protegidos, a desserialização será executada sem erros, mas todos os dados serão nulos.
Isaac Zais
2
@sports, você pode fazer isso em C # desserializando para uma dinâmica, mas o desempenho é muito melhor se você desserializar para um tipo conhecido.
PRMan
50

Às vezes eu prefiro 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
fonte
Uma vez exemplo de um caso em que este era útil era quando o objecto estava tentando deserialize em continha uma propriedade que era uma interface
soupy1976
2
Uma explicação estaria em ordem.
Peter Mortensen
Por que você prefere isso à resposta aceita por @Icarus?
Questionando
@Questionar, desserializar para classes de tipos fortes negligenciaria todas as propriedades que não estavam em suas classes, enquanto desserializar para objetos dinâmicos retornaria apenas um objeto .Net dinâmico que é flexível a qualquer nova propriedade criada no futuro sem a necessidade de atualizar suas classes. (como eu disse, às vezes não standard)
Bishoy Hanna
39

Uma ótima maneira de gerar automaticamente essas classes para você é copiar sua saída JSON e lançá-la aqui:

http://json2csharp.com/

Ele fornecerá um ponto de partida para retocar suas classes para desserialização.

Jack Fairfield
fonte
28

Com muita facilidade, podemos analisar o conteúdo JSON com a ajuda do dicionário e do JavaScriptSerializer. Aqui está o código de exemplo pelo qual analiso o conteúdo JSON de um arquivo 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
fonte
3
Essa solução é muito útil se você não tiver tempo ou precisar criar contratos de dados. Especialmente se você estiver interessado em apenas alguns atributos enterrados profundamente na estrutura JSON. Nessa situação, você pode usar uma série de instruções para navegar para o que precisa. Nota: o tipo a desserializar também pode ser um dos seguintes: Dictionary <string, object> ou ArrayList (quando um nó tem uma estrutura repetida).
Philippe Monnet
1
Recebo uma exceção de tempo de execução com isso: Nenhum construtor sem parâmetros definido para o tipo de 'System.String' na linha de código Deserialize.
RSK 23/05
20

Newtonsoft.JSONé uma boa solução para esse tipo de situação. Também Newtonsof.JSONé mais rápido do que outros, tais como JavaScriptSerializer, DataContractJsonSerializer.

Nesta amostra, você pode o seguinte:

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

Em seguida, você pode converter jsonData em JArraye pode usar um forloop para obter dados a cada iteração.

Além disso, quero adicionar algo:

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

Trabalhar com objetos dinâmicos e usar o Newtonsoft serialize é uma boa opção.

OnurBulbul
fonte
15

Concordo com Icarus (teria comentado se pudesse), mas, em vez de usar uma classe CustomObject , usaria um dicionário (caso o Facebook adicione algo).

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

ou

private class MyFacebookClass
{
    public IList<IDictionary<string, object>> data { get; set; }
}
Stijn Bollen
fonte
3
O uso dinâmico funciona melhor nas novas versões. public IList<IDictionary<string, dynmaic>> data { get; set; }
precisa saber é
3

Serialização:

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

Response.Write(jsonData);

Desserialização ::

Para desserializar um objeto dinâmico

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

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

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

Você pode usar essas extensões

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
fonte
1

Aqui está outro site que o ajudará com todo o código necessário, desde que você tenha disponível uma string JSON formatada corretamente:

https://app.quicktype.io/

Liknes
fonte
1

Se você estiver usando o .NET Core 3.0, poderá usar System.Text.Json (agora incorporado) para desserializar o JSON.

A primeira etapa é criar classes para modelar o JSON. Existem muitas ferramentas que podem ajudar nisso, e algumas das respostas aqui as listam.

Algumas opções são http://json2csharp.com , http://app.quicktype.io ou use o Visual Studio (menu EditarColar especialColar JSON como classes ).

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

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

Em seguida, você pode desserializar usando:

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

Se você precisar adicionar configurações, como camelCasemanipulação, passe as configurações do serializador para o desserializador da seguinte maneira:

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