Десериализовать JSON с помощью C #

206

Я пытаюсь десериализовать вызов API Graph у друга из Facebook в список объектов. Объект JSON выглядит следующим образом:

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

Это не работает, потому что примитивный объект недействителен. Как я могу десериализовать это?

Питер Мортенсен
источник
3
написать специальный десериализатор специально для обслуживания таких json ...
ашутош раина
2
или вы можете использовать Dictionary<string,string>, проверить: stackoverflow.com/questions/7699972/…
Kakashi
10
Ваш друг: json2csharp.com
nawfal
4
На самом деле визуальные студии (по состоянию на 2013 или 2012 год с установленными веб-инструментами) имеют такую ​​встроенную функциональность: Edit> Paste Special> Paste JSON As Classes
floomby

Ответы:

264

Вам нужно создать такую ​​структуру:

public class Friends
{

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

public class FacebookFriend
{

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

Тогда вы должны быть в состоянии сделать:

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

Имена моих классов - просто пример. Вы должны использовать собственные имена.

Добавление образца теста:

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

Производит:

id: 518523721, name: ftyft
id: 527032438, name: ftyftyf
id: 527572047, name: ftgft
id: 531141884, name: ftftft
Икар
источник
3
Да, это то, что я не хочу делать, создать новый объект для хранения детей. Я думаю, что я собираюсь вытащить json, извлекая примитивный объект. Спасибо.
@Kevin Holditch спасибо за исправление. Я пропустил один важный бит :)
Икар
2
Что мне не нравится в этом System.Web.Script.Serialization.JavaScriptSerializer (), так это то, что вам всегда нужен определенный тип T. В Java есть библиотека (пакет) org.java, которая остается анонимной: «JSONObject [» param "]. JSONarray (5)" и т. д.
спорт
2
Важно отметить, что установщики для свойств id и name должны оставаться открытыми. Если они установлены на частный или защищенный, десериализация будет выполнена без ошибок, но все данные будут нулевыми.
Исаак Заис
2
@sports, вы можете сделать это в C #, десериализовав в динамический, но производительность намного лучше, если вы десериализуете в известный тип.
PRMan
50

Иногда я предпочитаю динамические объекты:

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);
}
Бишой ханна
источник
Однажды пример того, где это было полезно, был, когда объект, в который я пытался десериализоваться, содержал свойство, которое было интерфейсом
souy1976
2
Объяснение будет в порядке.
Питер Мортенсен
Почему вы предпочитаете это принятому @Icarus ответу?
Опрос
@Questioning, десериализация в классы сильных типов будет игнорировать любые свойства, которых не было в ваших классах, в то время как десериализация в динамические объекты просто вернет динамический .Net-объект, который будет гибким для любого нового свойства, созданного в будущем, без необходимости обновления ваших классов. (как я уже говорил, иногда нестандартно)
Бишой Ханна
39

Отличный способ автоматически сгенерировать эти классы для вас - скопировать выходные данные JSON и добавить их сюда:

http://json2csharp.com/

Он предоставит вам отправную точку для подбора классов для десериализации.

Джек Фэйрфилд
источник
28

Очень легко мы можем проанализировать контент JSON с помощью словаря и JavaScriptSerializer. Вот пример кода, с помощью которого я анализирую содержимое JSON из файла 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();
Томас
источник
3
Это решение очень полезно, если у вас нет времени или необходимости создавать контракты данных. Особенно, если вам интересны только некоторые атрибуты, скрытые глубоко в структуре JSON. В этой ситуации вы можете использовать ряд утверждений, чтобы перейти к тому, что вам нужно. Примечание: тип для десериализации также может быть одним из следующих: Dictionary <string, object> или ArrayList (когда узел имеет повторяющуюся структуру).
Филипп Монне
1
Я получаю исключение времени выполнения с этим: не определен конструктор без параметров для типа 'System.String' в строке кода десериализации.
РСК
20

Newtonsoft.JSONявляется хорошим решением для подобных ситуаций. Также Newtonsof.JSONбыстрее, чем другие, такие как JavaScriptSerializer,DataContractJsonSerializer .

В этом примере вы можете следующее:

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

Затем вы можете привести jsonData к JArray, и вы можете использоватьfor цикл для получения данных на каждой итерации.

Также я хочу кое-что добавить:

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

Работа с динамическим объектом и использование Newtonsoft serialize - хороший выбор.

OnurBulbul
источник
15

Я согласен с Icarus (прокомментировал бы, если бы мог), но вместо использования класса CustomObject я бы использовал словарь (на случай, если Facebook что-то добавит).

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

или

private class MyFacebookClass
{
    public IList<IDictionary<string, object>> data { get; set; }
}
Стейн Боллен
источник
3
Использование динамического лучше работает в новых версиях. public IList<IDictionary<string, dynmaic>> data { get; set; }
BJury
3

Сериализация:

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

Response.Write(jsonData);

Десериализация: :

Для десериализации динамического объекта

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

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

Response.Write(res.Name);
Равула Сандип
источник
3

Вы можете использовать это расширение

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);
   }
}
Хидает Р. Колкусу
источник
1

Вот еще один сайт, который поможет вам со всем необходимым кодом, если у вас есть правильно отформатированная строка JSON:

https://app.quicktype.io/

Liknes
источник
1

Если вы используете .NET Core 3.0, вы можете использовать System.Text.Json (который теперь встроен) для десериализации JSON.

Первым шагом является создание классов для моделирования JSON. Есть много инструментов, которые могут помочь с этим, и некоторые ответы здесь перечисляют их.

Некоторые варианты: http://json2csharp.com , http://app.quicktype.io или используйте Visual Studio (меню « Правка» → « Специальная вставка» → « Вставить JSON в качестве классов» ).

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

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

Затем вы можете десериализовать с помощью:

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

Если вам нужно добавить настройки, такие как camelCaseобработка, передайте настройки сериализатора в десериализатор следующим образом:

var options = new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
var person = JsonSerializer.Deserialize<Response>(json, options);
Haldo
источник