1. Вступ
Якщо ви лише починаєте знайомитися із серіалізацією в .NET, цілком природно запитати: навіщо ще одна бібліотека, якщо вже є вбудований System.Text.Json? Відповідь проста: Newtonsoft.Json зʼявилася раніше й за роки стала одним із найгнучкіших інструментів для роботи з JSON у .NET.
Вона стала де-факто стандартом, адже підтримує складні сценарії: користувацькі контракти, потужні конвертери, серіалізацію приватних полів, LINQ до JSON, динамічні обʼєкти (JObject), гнучку обробку циклічних посилань і численні формати дат і часу. Багато бібліотек і API досі використовують Json.NET «під капотом».
Важливо: у низці сценаріїв вбудований System.Text.Json поки що поступається можливостям Newtonsoft.Json, тож вивчення Json.NET залишається актуальним.
Як підʼєднати Newtonsoft.Json (Json.NET)
Встановіть пакет через NuGet:
dotnet add package Newtonsoft.Json
Імпортуйте простір імен:
using Newtonsoft.Json;
2. Серіалізація через Newtonsoft.Json
Візьмемо традиційний клас Person:
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
Серіалізація обʼєкта у рядок JSON
Person person = new Person { Name = "Іван", Age = 30 };
// Серіалізація в JSON
string json = JsonConvert.SerializeObject(person);
Console.WriteLine(json);
// Виведення: {"Name":"Іван","Age":30}
Десеріалізація JSON назад у обʼєкт
string json = "{\"Name\":\"Іван\",\"Age\":30}";
Person person = JsonConvert.DeserializeObject<Person>(json);
Console.WriteLine($"{person.Name}, {person.Age}");
// Виведення: Іван, 30
Що відбувається «під капотом»?
Newtonsoft.Json перебирає всі відкриті властивості (public), серіалізує їх у JSON і формує рядок. Під час десеріалізації він зіставляє ключі з JSON з іменами властивостей і заповнює обʼєкт.
3. Серіалізація колекцій обʼєктів
Серіалізація колекцій і масивів
З колекціями усе працює «з коробки».
List<Person> people = new List<Person>
{
new Person { Name = "Іван", Age = 30 },
new Person { Name = "Марія", Age = 25 }
};
string json = JsonConvert.SerializeObject(people);
// Виведення: [{"Name":"Іван","Age":30},{"Name":"Марія","Age":25}]
List<Person> deserialized = JsonConvert.DeserializeObject<List<Person>>(json);
// Тепер у вас знову список Person!
Особливості серіалізації та десеріалізації словників
var dict = new Dictionary<string, int>
{
["apple"] = 2,
["banana"] = 5
};
string json = JsonConvert.SerializeObject(dict);
// Виведення: {"apple":2,"banana":5}
var deserializedDict = JsonConvert.DeserializeObject<Dictionary<string,int>>(json);
// Усе працює!
Якщо ключі не рядкові (наприклад, Dictionary<int,string>), Json.NET перетворює ключі на рядки під час серіалізації, а під час десеріалізації спробує перетворити їх назад. Для складних ключів (наприклад, Guid) надійніше використовувати Dictionary<string, TValue>.
4. Робота з вкладеними обʼєктами та ієрархіями
public class Order
{
public int Id { get; set; }
public Person Customer { get; set; }
public List<Product> Products { get; set; }
}
public class Product
{
public string Title { get; set; }
public double Price { get; set; }
}
Order order = new Order
{
Id = 123,
Customer = new Person { Name = "Іван", Age = 30 },
Products = new List<Product>
{
new Product { Title = "Ноутбук", Price = 50000.0 },
new Product { Title = "Миша", Price = 1500.0 }
}
};
string json = JsonConvert.SerializeObject(order);
Console.WriteLine(json);
Результат: вкладені обʼєкти коректно подано всередині JSON-структури.
5. Налаштування серіалізації за допомогою атрибутів
Ігноруємо властивість
public class Person
{
public string Name { get; set; }
[JsonIgnore]
public int Age { get; set; }
}
Тепер Age не потрапить у JSON.
Перейменовуємо властивість
public class Person
{
[JsonProperty("full_name")]
public string Name { get; set; }
}
У JSON імʼя матиме вигляд "full_name".
6. Гнучкі налаштування: JsonSerializerSettings
Форматування (читабельний багаторядковий JSON):
string json = JsonConvert.SerializeObject(
people,
Formatting.Indented
);
Результат:
[
{
"Name": "Іван",
"Age": 30
},
{
"Name": "Марія",
"Age": 25
}
]
Часто вживані налаштування:
| Властивість | Опис |
|---|---|
|
Як обробляти властивості зі значенням null (пропускати їх чи записувати явне null) |
|
Чи пропускати значення за замовчуванням |
|
Що робити з циклічними посиланнями |
|
Формат рядкового представлення дат і часу |
Приклад із пропуском null:
string json = JsonConvert.SerializeObject(
person,
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }
);
7. Робота з динамічними JSON-структурами: JObject, JArray та ін.
Коли структура JSON наперед невідома, використовуйте типи з Newtonsoft.Json.Linq:
using Newtonsoft.Json.Linq;
string json = @"{
'Name': 'Іван',
'Age': 30,
'Skills': ['C#', 'SQL', 'JSON']
}";
JObject obj = JObject.Parse(json);
Console.WriteLine(obj["Name"]); // Іван
Console.WriteLine(obj["Skills"][0]); // C#
Створення JSON «на льоту»:
var jObj = new JObject
{
["Status"] = "Success",
["Result"] = new JArray("item1", "item2", "item3")
};
Console.WriteLine(jObj.ToString(Formatting.Indented));
JObject і JArray — представлення JSON-обʼєкта та масиву, по суті — зручні колекції.
8. Корисні нюанси
Циклічні посилання
Newtonsoft.Json вміє гнучко їх обробляти:
var settings = new JsonSerializerSettings
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
};
string json = JsonConvert.SerializeObject(obj, settings);
Тоді цикли буде пропущено. Щоб зберігати посилання, можна використати ReferenceLoopHandling.Serialize разом із [JsonObject(IsReference = true)].
Серіалізація анонімних і динамічних обʼєктів
var anon = new { Foo = 42, Bar = "Hello" };
string json = JsonConvert.SerializeObject(anon);
// {"Foo":42,"Bar":"Hello"}
Валідація та обробка помилок
try
{
Person p = JsonConvert.DeserializeObject<Person>(brokenJson);
}
catch (JsonSerializationException ex)
{
Console.WriteLine("Помилка під час десеріалізації: " + ex.Message);
}
Порівняння Newtonsoft.Json vs System.Text.Json
| Newtonsoft.Json (Json.NET) | System.Text.Json (.NET) | |
|---|---|---|
| Підтримка .NET | .NET Framework/Standard/6+ | .NET Core 3.0+ / .NET 5/6/9 |
| LINQ до JSON (JObject/JArray) | Так | Ні |
| Гнучке налаштування | Дуже гнучке | Обмежене |
| Атрибути ([JsonProperty], ...) | Так | Так (частково, менше можливостей) |
| Підтримка приватних властивостей | Так | Ні |
| Швидкість | Повільніше в низці сценаріїв | Швидше |
| Складні конвертери | Так | Так (менш гнучко, поки що) |
| Підтримка DataTable, DataSet | Так | Ні |
| Документація та приклади | Багато | Поступово зростає |
9. Помилки новачків і типові підводні камені
Помилка № 1: властивості отримують значення null після десеріалізації.
Часто у властивості відсутній сетер або немає конструктора без параметрів — серіалізатору нічим заповнити обʼєкт.
Помилка № 2: невідповідність імен властивостей між JSON і класом.
Якщо в JSON поле "fullName", а в класі — FullName, використовуйте [JsonProperty] або налаштуйте ContractResolver для зіставлення імен.
Помилка № 3: серіалізація за замовчуванням працює лише з публічними властивостями.
Приватні поля/властивості не серіалізуються без додаткових налаштувань. Потрібні конвертери або спеціальні резолвери/контракти.
Помилка № 4: циклічні посилання призводять до StackOverflowException.
Взаємні посилання обʼєктів зациклюють серіалізацію без налаштувань. Налаштуйте обробку посилань (наприклад, ReferenceLoopHandling) або змініть модель даних.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ