1. Введение
Newtonsoft.Json — это своего рода динозавр в хорошем смысле слова. Он был де-факто стандартом для работы с JSON в экосистеме .NET на протяжении многих лет, ещё до того, как System.Text.Json вообще появился на свет. Миллионы проектов, тысячи библиотек и фреймворков (даже многие части ASP.NET Core до недавнего времени) использовали именно Json.NET.
Его преимущества в том, что он:
- Богат функционалом и гибок: Json.NET предлагает огромное количество настроек, атрибутов и возможностей для кастомизации процесса сериализации и десериализации. Он умеет делать вещи, которые System.Text.Json либо делает с большим трудом, либо вообще не умеет.
- Лоялен к "неидеальному" JSON: данные из внешних систем не всегда идеальны — Json.NET чаще терпим к таким случаям и позволяет десериализовать без лишней боли.
- Обратно совместим: если проект или библиотека завязаны на Json.NET, умение работать с ним остаётся необходимым.
Конечно, System.Text.Json быстрее и создан с учётом современных требований. Но Newtonsoft.Json до сих пор остаётся мощным инструментом, особенно если нужна специфическая логика или максимальная гибкость.
Как установить Newtonsoft.Json?
Поскольку это сторонняя библиотека, добавьте пакет через NuGet:
- Откройте проект.
- Кликните правой кнопкой по проекту в Solution Explorer.
- Выберите "Manage NuGet Packages...".
- В поиске введите Newtonsoft.Json.
- Выберите пакет и нажмите "Install".
После установки появится новая зависимость — можно использовать Json.NET!
Сравнение возможностей Newtonsoft.Json и System.Text.Json
| Возможность | System.Text.Json | Newtonsoft.Json |
|---|---|---|
| Простая сериализация/десериализация | Да | Да |
| Поддержка атрибутов для свойств | Частично | Полная |
| Кастомные конвертеры | Да | Да |
| Работа с приватными полями | Нет | Да |
| Работа с динамическими структурами | Ограниченно | Да |
| LINQ to JSON (JObject/JArray) | Нет | Да |
| Reference Loop Handling | Да | Да |
| Поддержка DataTable, DataSet и сложных типов | Нет | Да |
| Производительность | Лучше | Хорошая |
2. Пример сериализации и десериализации простого объекта
Возьмём общую игровую структуру, которая развивается из лекции в лекцию:
public class Player
{
public string Name { get; set; }
public int Health { get; set; }
public bool IsAlive { get; set; }
public List<string> Inventory { get; set; }
public Position Position { get; set; }
}
public class Position
{
public int X { get; set; }
public int Y { get; set; }
}
Теперь сохраним объект Player в JSON и восстановим его:
using Newtonsoft.Json;
Player player1 = new Player
{
Name = "Aragorn",
Health = 100,
IsAlive = true,
Inventory = new List<string> { "sword", "bow", "healing potion" },
Position = new Position { X = 10, Y = 25 }
};
// Сериализация в JSON-строку
string json = JsonConvert.SerializeObject(player1, Formatting.Indented);
Console.WriteLine(json);
// Десериализация обратно в объект Player
Player player2 = JsonConvert.DeserializeObject<Player>(json);
Console.WriteLine($"Имя: {player2.Name}, здоровье: {player2.Health}");
Всё? Да, почти, но это только верхушка айсберга. Давайте разберём, чем Newtonsoft.Json интереснее и гибче других библиотек.
3. Форматирование, настройки и расширенные параметры
Когда сериализуете объект, можете получать как компактную строку, так и красиво отформатированный JSON. Поведение контролируется параметрами и настройками.
Пример: Разные варианты форматирования
// Красиво читабельный JSON
string prettyJson = JsonConvert.SerializeObject(player1, Formatting.Indented);
// Компактный "минифицированный" JSON
string compactJson = JsonConvert.SerializeObject(player1, Formatting.None);
Настройки сериализации
При необходимости передавайте JsonSerializerSettings для тонкой настройки:
var settings = new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore, // Пропускать поля со значением null
DefaultValueHandling = DefaultValueHandling.Ignore, // Пропускать поля с дефолтом
Formatting = Formatting.Indented
};
string customJson = JsonConvert.SerializeObject(player1, settings);
Вы получаете максимальный контроль над форматом вывода: хотите пропустить пустые поля — пожалуйста. Нужно сериализовать даже приватные свойства — настройте контракт.
4. Управление полями и свойствами с помощью атрибутов
Newtonsoft.Json поддерживает мощную систему атрибутов, которые настраивают сериализацию прямо в классе.
JsonProperty — Переименование свойств
Если JSON-протокол требует иного имени поля:
public class Player
{
[JsonProperty("player_name")]
public string Name { get; set; }
// ...
}
Результирующий JSON:
{ "player_name": "Aragorn", ... }
JsonIgnore — Игнорировать свойство
public class Player
{
[JsonIgnore]
public int Health { get; set; }
}
Теперь поле Health пропадёт при сериализации.
JsonConverter — Кастомные преобразования
Позволяет указать, каким конвертером обрабатывать конкретное поле.
public class Player
{
[JsonConverter(typeof(InventoryToStringConverter))]
public List<string> Inventory { get; set; }
}
(Подробнее о конвертерах — ниже.)
5. Работа с вложенными и коллекциями объектов
Json.NET отлично справляется с вложенными объектами, массивами, коллекциями, словарями.
Пример: Словари
public class GameStats
{
public Dictionary<string, int> Scores { get; set; }
}
GameStats stats = new GameStats
{
Scores = new Dictionary<string, int>
{
["Alice"] = 1023,
["Bob"] = 999
}
};
string statsJson = JsonConvert.SerializeObject(stats, Formatting.Indented);
Console.WriteLine(statsJson);
JSON получится вот такой:
{
"Scores": {
"Alice": 1023,
"Bob": 999
}
}
6. Cложные структуры: циклические ссылки, Self-Referencing Objects
Иногда объекты содержат ссылки друг на друга. Newtonsoft.Json поддерживает сериализацию таких структур через специальные настройки.
Пример: Разрешение циклических ссылок
public class Person
{
public string Name { get; set; }
public Person Parent { get; set; }
public List<Person> Children { get; set; }
}
// Настраиваем сериализацию для циклов
var settings = new JsonSerializerSettings
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore // или .Serialize
};
Person p1 = new Person { Name = "Папа" };
Person p2 = new Person { Name = "Сын", Parent = p1 };
p1.Children = new List<Person> { p2 };
string json = JsonConvert.SerializeObject(p1, settings);
Console.WriteLine(json);
По умолчанию, если оставить ReferenceLoopHandling = Error, вы получите исключение. Это защищает от случайной бесконечной сериализации.
7. Работа с динамическими структурами: JObject, JArray
Когда структура JSON заранее неизвестна или меняется на лету, используйте динамические объекты без строгой типизации на уровне C#.
Основные типы:
- JObject — представление JSON-объекта.
- JArray — представление массива.
using Newtonsoft.Json.Linq;
// Преобразование строки в JObject
string json = @"{ 'name': 'Aragorn', 'health': 100 }";
JObject obj = JObject.Parse(json);
Console.WriteLine((string)obj["name"]); // Aragorn
Console.WriteLine((int)obj["health"]); // 100
// Динамическое добавление свойств
obj["class"] = "Ranger";
Console.WriteLine(obj.ToString());
Итерация по массиву
string jsonArr = @"['apple', 'banana', 'cherry']";
JArray array = JArray.Parse(jsonArr);
foreach (JToken item in array)
{
Console.WriteLine(item);
}
8. Поддержка версионности и обязательных полей
Формат JSON может меняться, поля могут отсутствовать. Используйте атрибуты и настройки:
- [JsonProperty(Required = Required.Always)] — требовать наличие поля (иначе исключение).
- [JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)] — подставить дефолт, если поле отсутствует.
public class Player
{
[JsonProperty(Required = Required.Always)]
public string Name { get; set; }
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
[DefaultValue(50)]
public int Health { get; set; }
}
9. Преобразование дат и форматов времени
Работа с датами часто требует явного формата.
var dateSettings = new JsonSerializerSettings
{
DateFormatString = "yyyy-MM-dd"
};
string json = JsonConvert.SerializeObject(DateTime.Now, dateSettings);
Console.WriteLine(json); // "2024-06-15"
И обратно при десериализации:
string dateJson = "\"2024-06-15\""; // Обратите внимание: это строка в кавычках!
DateTime dt = JsonConvert.DeserializeObject<DateTime>(dateJson);
Console.WriteLine(dt);
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ