Десеріалізація JSON в .NET-об’єкті за допомогою Newtonsoft (або LINQ до JSON, можливо?)


318

Я знаю, що є кілька дописів про Newtonsoft, тому, сподіваюся, це не зовсім повторення ... Я намагаюся перетворити дані JSON, повернені API Kazaa, в хороший об’єкт якогось роду

WebClient client = new WebClient();
Stream stream = client.OpenRead("http://api.kazaa.com/api/v1/search.json?q=muse&type=Album");
StreamReader reader = new StreamReader(stream);

List<string> list = Newtonsoft.Json.JsonConvert.DeserializeObject<List<string>>(reader.Read().ToString());

foreach (string item in list)
{
    Console.WriteLine(item);
}

//Console.WriteLine(reader.ReadLine());
stream.Close();

Ця лінія JsonConvert - це лише остання, яку я намагався ... Я не зовсім отримую це і сподівався усунути якусь роботу, просячи вас, хлопці. Я спочатку намагався перетворити його у словник чи щось таке ... а насправді мені просто потрібно зафіксувати пару значень, щоб, судячи з документації, можливо, LINQ Ньютонсофта в JSON може бути кращим вибором? Думки / Посилання?

Ось приклад повернення даних JSON:

{
  "page": 1,
  "total_pages": 8,
  "total_entries": 74,
  "q": "muse",
  "albums": [
    {
      "name": "Muse",
      "permalink": "Muse",
      "cover_image_url": "http://image.kazaa.com/images/69/01672812 1569/Yaron_Herman_Trio/Muse/Yaron_Herman_Trio-Muse_1.jpg",
      "id": 93098,
      "artist_name": "Yaron Herman Trio"
    },
    {
      "name": "Muse",
      "permalink": "Muse",
      "cover_image_url": "htt p://image.kazaa.com/images/54/888880301154/Candy_Lo/Muse/Candy_Lo-Muse_1.jpg",
      "i d": 102702,
      "artist_name": "\u76e7\u5de7\u97f3"
    },
    {
      "name": "Absolution",
      "permalink": " Absolution",
      "cover_image_url": "http://image.kazaa.com/images/65/093624873365/Mus e/Absolution/Muse-Absolution_1.jpg",
      "id": 48896,
      "artist_name": "Muse"
    },
    {
      "name": "Ab solution",
      "permalink": "Absolution-2",
      "cover_image_url": "http://image.kazaa.com/i mages/20/825646911820/Muse/Absolution/Muse-Absolution_1.jpg",
      "id": 118573,
      "artist _name": "Muse"
    },
    {
      "name": "Black Holes And Revelations",
      "permalink": "Black-Holes-An d-Revelations",
      "cover_image_url": "http://image.kazaa.com/images/66/093624428466/ Muse/Black_Holes_And_Revelations/Muse-Black_Holes_And_Revelations_1.jpg",
      "id": 48813,
      "artist_name": "Muse"
    },
    {
      "name": "Black Holes And Revelations",
      "permalink": "Bla ck-Holes-And-Revelations-2",
      "cover_image_url": "http://image.kazaa.com/images/86/ 825646911486/Muse/Black_Holes_And_Revelations/Muse-Black_Holes_And_Revelations_1 .jpg",
      "id": 118543,
      "artist_name": "Muse"
    },
    {
      "name": "Origin Of Symmetry",
      "permalink": "Origin-Of-Symmetry",
      "cover_image_url": "http://image.kazaa.com/images/29/825646 912629/Muse/Origin_Of_Symmetry/Muse-Origin_Of_Symmetry_1.jpg",
      "id": 120491,
      "artis t_name": "Muse"
    },
    {
      "name": "Showbiz",
      "permalink": "Showbiz",
      "cover_image_url": "http: //image.kazaa.com/images/68/825646182268/Muse/Showbiz/Muse-Showbiz_1.jpg",
      "id": 60444,
      "artist_name": "Muse"
    },
    {
      "name": "Showbiz",
      "permalink": "Showbiz-2",
      "cover_imag e_url": "http://image.kazaa.com/images/50/825646912650/Muse/Showbiz/Muse-Showbiz_ 1.jpg",
      "id": 118545,
      "artist_name": "Muse"
    },
    {
      "name": "The Resistance",
      "permalink": "T he-Resistance",
      "cover_image_url": "http://image.kazaa.com/images/36/825646864836/ Muse/The_Resistance/Muse-The_Resistance_1.jpg",
      "id": 121171,
      "artist_name": "Muse"
    }
  ],
  "per_page": 10
}

Я трохи більше читав і виявив, що LINQ Ньютонафта до JSON - це саме те, що я хотів ... за допомогою WebClient, Stream, StreamReader та Newtonsoft ... Я можу натиснути Kazaa на дані JSON, вилучити URL, завантажити файл і зробити це все як сім рядків коду! Я це люблю.

WebClient client = new WebClient();
Stream stream = client.OpenRead("http://api.kazaa.com/api/v1/search.json?q=muse&type=Album");
StreamReader reader = new StreamReader(stream);

Newtonsoft.Json.Linq.JObject jObject = Newtonsoft.Json.Linq.JObject.Parse(reader.ReadLine());

// Instead of WriteLine, 2 or 3 lines of code here using WebClient to download the file
Console.WriteLine((string)jObject["albums"][0]["cover_image_url"]);
stream.Close();

Ця публікація отримує стільки звернень. Я подумав, що може бути корисним включити біти "використання", які обговорюються в коментарях.

using(var client = new WebClient())
using(var stream = client.OpenRead("http://api.kazaa.com/api/v1/search.json?q=muse&type=Album"))
using (var reader = new StreamReader(stream))
{
    var jObject = Newtonsoft.Json.Linq.JObject.Parse(reader.ReadLine());
    Console.WriteLine((string) jObject["albums"][0]["cover_image_url"]);
}

6
Елегантний приклад, дякую. Лише пропозиція: можливо, ви залишили це для короткості, але оскільки WebClient, Streamі StreamReaderвсе реалізуйте IDisposable, ви можете додати кілька usingкодів у свій код.
arcain

ага так, хороший дзвінок ... (так, це насправді просто консольний додаток, я дуже швидко працював над дослідженнями завдань, які я придумував) Тепер перейшов до дослідження останнього фрагмента головоломки, HLS + AES-шифрування :) ... lol
J Benjamin

1
+1 Дякуємо за публікацію прикладу Linq. Саме те, що мені було потрібно.
Марк Вілкінс

Чи також рішення ньютоншфт не повністю десеріалізує JSON? Як і рішення @ arcain.
AXMIM

Зверніть увагу на посилання тут: LINQ - JSON
ю ян Цзянь

Відповіді:


259

Якщо вам просто потрібно отримати кілька об'єктів від об'єкта JSON, я б використав LINQ Json.NET для JObjectкласу JSON . Наприклад:

JToken token = JObject.Parse(stringFullOfJson);

int page = (int)token.SelectToken("page");
int totalPages = (int)token.SelectToken("total_pages");

Мені подобається такий підхід, оскільки вам не потрібно повністю дезаріалізувати об’єкт JSON. Це корисно з API, які іноді можуть здивувати вас відсутніми властивостями об’єкта, як, наприклад, Twitter.

Документація: Серіалізація та десеріалізація JSON з Json.NET та LINQ в JSON з Json.NET


1
Так, я насправді трохи більше читав і тестував ... Я вважав, що це також хороший спосіб зробити це ... Ньютонсофт, досить приємна бібліотека, я викладу свій приклад для інших
Дж. Бенджамін,

1
розмістив приблизний приклад того, як я це робив ... не зовсім те саме, я бачу, ти запропонував JToken.Parse ... не впевнений у відмінностях між двома, але так, хороший матеріал!
Дж. Бенджамін

1
@Jbenjamin Дякую! Це був друкарський помилок. JToken є базовим класом для JObject, і це лише моя особиста перевага працювати з більш абстрактним типом. Дякую, що зателефонували мені на це.
arcain

Вибачте, але це повинен бути JToken або JObject? Наведений вище код все ще кидає помилку "Помилка читання JObject з JsonReader" раз у раз.
TYRONEMICHAEL

1
@Tyrone Звичайно, немає проблем. Я фактично використовую цей код і для розбору статусу Twitter, і мені довелося писати зовсім небагато помилок при обробці дзвінків у Twitter, оскільки вони часом можуть бути непомітними. Якщо ви цього ще не робите, я рекомендую перенести необроблену відповідь JSON з Twitter в журнал, перш ніж намагатися її розібрати. Тоді, якщо це не вдасться, ви можете принаймні побачити, чи отримали ви щось фанк через дріт.
arcain

272

Ви можете використовувати dynamicтип C # для спрощення речей. Ця методика також робить ре-факторинг простішим, оскільки він не покладається на магічні струни.

JSON

Рядок JSON нижче - це проста відповідь на дзвінок HTTP API, і він визначає два властивості: Idі Name.

{"Id": 1, "Name": "biofractal"}

C #

Використовуйте JsonConvert.DeserializeObject<dynamic>()для деріаріалізації цього рядка в динамічний тип, а потім просто отримайте доступ до його властивостей звичайним способом.

dynamic results = JsonConvert.DeserializeObject<dynamic>(json);
var id = results.Id;
var name= results.Name;

Якщо ви вкажете тип results змінної як dynamic, а не використовувати varключове слово, то значення властивостей будуть правильно деріаріалізуватись, наприклад, Idдо an, intа не a JValue(завдяки GFoley83 за коментар нижче).

Примітка . Посилання NuGet для складання Newtonsoft - це http://nuget.org/packages/newtonsoft.json .

Пакет : Ви також можете додати пакунок із програмним інсталятором, з відкритим проектом, просто перегляньте пакет, а потім просто встановіть його встановіть, видаліть, оновіть , він буде просто доданий у ваш проект у розділі Dependpendes / NuGet


Я використовував той самий фрагмент коду, що і вище, щоб дезаріалізувати відповідь щебетання з newtonsoft.dll версії 4.5.6, і він працював нормально ... але після оновлення до версії 5.0.6 .. він почав кидати помилку ... будь-яка ідея чому ??
Пранів

1
Добре для динамічного об'єкта, коли ми знаємо чи у нас є клас #, тому ми можемо споживати як клас C # замість динамічного, наприклад, <Myclass>.
MSTdev

2
Використовуйте dynamic results = JsonConvert.DeserializeObject<ExpandoObject>(json);тут FTW. Це правильно деріаріалізувати Idдо int, а не до a JValue. Дивіться тут: dotnetfiddle.net/b0WxGJ
GFoley83

@biofractal Як би це зробити dynamic results = JsonConvert.DeserializeObject<dynamic>(json); у VB.NET? Dim results As Object = Newtonsoft.Json.JsonConvert.DeserializeObject(Of Object)(json)не працює.
Flo


41

За допомогою dynamicключового слова стає дуже легко проаналізувати будь-який об’єкт такого типу:

dynamic x = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonString);
var page = x.page;
var total_pages = x.total_pages
var albums = x.albums;
foreach(var album in albums)
{
    var albumName = album.name;

    // Access album data;
}

Мені хотілося знати, як переглядати результати, і це зайняло занадто довго, щоб знайти ... дякую !!
batoutofhell

22

Виправте мене, якщо я помиляюся, але попередній приклад, я вважаю, лише трохи не синхронізований з останньою версією бібліотеки Джейсона Ньютона Джеймса Ньютона.

var o = JObject.Parse(stringFullOfJson);
var page = (int)o["page"];
var totalPages = (int)o["total_pages"];

1
дякую за вашу відповідь Рік, я схоже на приклади, які я знайшов і в останній документації.
Дж. Бенджамін

1
Так, оскільки аркайн виправив друкарську помилку, тепер мій коментар просто виглядає нерозумним: '(. Спочатку я розміщував, бо не впізнав JToken.Parse.
Rick

1
Зовсім не дурний - напевно була помилка, і завжди існує більше ніж один спосіб зробити це. До речі, моя версія Json.NET підтримує синтаксис за допомогою індексатора JObject, але код, який я змінив для своєї відповіді, був витягнутий з коду, використовуючи перевантаження SelectTokenметоду, щоб я міг придушити винятки, якщо маркер не був знайдено:, JToken JToken.SelectToken(string tokenName, bool errorWhenNoMatch)отже, звідки походить багатослівність.
arcain

18

Якщо, як і я, ви віддаєте перевагу поводженню з сильно набраними об’єктами **:

MyObj obj =  JsonConvert.DeserializeObject<MyObj>(jsonString);

Таким чином ви можете використовувати intellisense та компілювати перевірку помилок типу часу.

Ви можете легко створити необхідні об'єкти, скопіювавши свій JSON в пам'ять і вставивши його як об’єкти JSON (Visual Studio -> Редагувати -> Спеціальна вставка -> Вставити JSON як класи).

Дивіться тут, якщо у вас немає такої опції у Visual Studio.

Вам також потрібно буде переконатися, що ваш JSON дійсний. Додайте власний об’єкт на початку, якщо це лише масив об’єктів. тобто { "obj": [{}, {}, {}]}

** Я знаю, що динаміка полегшує справи іноді, але я трохи ol'skool з цим.


1
Дуже сподобався моєму підходу до програмування. Мені подобаються сильні набрані об’єкти. Дякуємо, що я використав і змінив цей код.
j.hull

11

Динамічний список слабо набраний - десеріалізуйте та прочитайте значення

// First serializing
dynamic collection = new { stud = stud_datatable }; // The stud_datable is the list or data table
string jsonString = JsonConvert.SerializeObject(collection);


// Second Deserializing
dynamic StudList = JsonConvert.DeserializeObject(jsonString);

var stud = StudList.stud;
foreach (var detail in stud)
{
    var Address = detail["stud_address"]; // Access Address data;
}

8

Мені подобається цей метод:

using Newtonsoft.Json.Linq;
// jsonString is your JSON-formatted string
JObject jsonObj = JObject.Parse(jsonString);
Dictionary<string, object> dictObj = jsonObj.ToObject<Dictionary<string, object>>();

Тепер ви можете отримати доступ до всього, що ви хочете, використовуючи dictObjяк словник. Ви також можете використовуватиDictionary<string, string> якщо ви бажаєте отримувати значення як рядки.

Ви можете використовувати цей самий метод для передачі, як і будь-який тип об’єкта .NET.


2
Я вважаю цей метод дуже приємним з двох причин: 1) коли ти не переймаєшся типом даних (усе є рядковим), і 2) зручно працювати зі словником значень
netfed

7

Крім того, якщо ви просто шукаєте певне значення, вкладене в вміст JSON, ви можете зробити щось подібне:

yourJObject.GetValue("jsonObjectName").Value<string>("jsonPropertyName");

І так звідти.

Це може допомогти, якщо ви не хочете нести витрати на перетворення всього JSON в об’єкт C #.


2

я створив клас Extionclas для json:

 public static class JsonExtentions
    {
        public static string SerializeToJson(this object SourceObject) { return Newtonsoft.Json.JsonConvert.SerializeObject(SourceObject); }


        public static T JsonToObject<T>(this string JsonString) { return (T)Newtonsoft.Json.JsonConvert.DeserializeObject<T>(JsonString); }
}

Дизайн-шаблон:

 public class Myobject
    {
        public Myobject(){}
        public string prop1 { get; set; }

        public static Myobject  GetObject(string JsonString){return  JsonExtentions.JsonToObject<Myobject>(JsonString);}
        public  string ToJson(string JsonString){return JsonExtentions.SerializeToJson(this);}
    }

Використання:

   Myobject dd= Myobject.GetObject(jsonstring);

                 Console.WriteLine(dd.prop1);


1

Досить спізнився на цю партію, але я сам сьогодні на роботі натрапив на це питання. Ось як я вирішив питання.

Я звертався до стороннього API, щоб отримати список книг. Об'єкт повернув масивний JSON-об'єкт, що містить приблизно 20+ полів, з яких мені потрібен був лише ідентифікатор як об'єкт ряду List. Я використовував linq на динамічному об'єкті, щоб отримати потрібне мені поле, а потім вставив його в мій об'єкт рядка List.

dynamic content = JsonConvert.DeserializeObject(requestContent);
var contentCodes = ((IEnumerable<dynamic>)content).Where(p => p._id != null).Select(p=>p._id).ToList();

List<string> codes = new List<string>();

foreach (var code in contentCodes)
{
    codes.Add(code?.ToString());
}

0

Нарешті, отримайте ім'я штату від JSON

Дякую!

Imports System
Imports System.Text
Imports System.IO
Imports System.Net
Imports Newtonsoft.Json
Imports Newtonsoft.Json.Linq
Imports System.collections.generic

Public Module Module1
    Public Sub Main()

         Dim url As String = "http://maps.google.com/maps/api/geocode/json&address=attur+salem&sensor=false"
            Dim request As WebRequest = WebRequest.Create(url)
        dim response As WebResponse = DirectCast(request.GetResponse(), HttpWebResponse)
        dim reader As New StreamReader(response.GetResponseStream(), Encoding.UTF8)
          Dim dataString As String = reader.ReadToEnd()

        Dim getResponse As JObject = JObject.Parse(dataString)

        Dim dictObj As Dictionary(Of String, Object) = getResponse.ToObject(Of Dictionary(Of String, Object))()
        'Get State Name
        Console.WriteLine(CStr(dictObj("results")(0)("address_components")(2)("long_name")))
    End Sub
End Module
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.