1. Giới thiệu
Newtonsoft.Json — về cơ bản là một "đồ già" theo nghĩa tốt. Nó từng là tiêu chuẩn de-facto để làm việc với JSON trong hệ sinh thái .NET suốt nhiều năm, ngay cả trước khi System.Text.Json xuất hiện. Hàng triệu project, hàng nghìn thư viện và framework (thậm chí nhiều phần của ASP.NET Core trước đây) dùng Json.NET.
Ưu điểm của nó là:
- Chức năng phong phú và linh hoạt: Json.NET có vô số setting, attribute và khả năng tùy biến cho quá trình serialization/deserialization. Nó làm được nhiều thứ mà System.Text.Json làm khó hơn hoặc không làm được.
- Khoan dung với JSON "không hoàn hảo": dữ liệu từ hệ thống bên ngoài không luôn sạch — Json.NET thường chịu đựng tốt hơn và cho phép deserialize mà ít đau hơn.
- Tương thích ngược: nếu project hoặc thư viện của bạn phụ thuộc vào Json.NET thì vẫn cần biết dùng nó.
Tất nhiên, System.Text.Json nhanh hơn và được thiết kế theo yêu cầu hiện đại. Nhưng Newtonsoft.Json vẫn là một công cụ mạnh, đặc biệt khi bạn cần logic đặc thù hoặc tối đa tính linh hoạt.
Cách cài Newtonsoft.Json?
Vì đây là thư viện bên ngoài, thêm package qua NuGet:
- Mở dự án.
- Nhấp chuột phải vào project trong Solution Explorer.
- Chọn "Manage NuGet Packages...".
- Trong ô tìm kiếm nhập Newtonsoft.Json.
- Chọn package và nhấn "Install".
Sau khi cài xong sẽ có dependency mới — giờ có thể dùng Json.NET!
So sánh khả năng của Newtonsoft.Json và System.Text.Json
| Tính năng | System.Text.Json | Newtonsoft.Json |
|---|---|---|
| Serialize/deserialize đơn giản | Có | Có |
| Hỗ trợ attribute cho properties | Một phần | Đầy đủ |
| Custom converters | Có | Có |
| Làm việc với trường private | Không | Có |
| Làm việc với cấu trúc động | Hạn chế | Có |
| LINQ to JSON (JObject/JArray) | Không | Có |
| Reference Loop Handling | Có | Có |
| Hỗ trợ DataTable, DataSet và kiểu phức tạp | Không | Có |
| Hiệu năng | Tốt hơn | Ổn |
2. Ví dụ serialize và deserialize đối tượng đơn giản
Lấy cấu trúc game chung mà ta sẽ phát triển dần trong các bài:
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; }
}
Bây giờ lưu đối tượng Player thành JSON và khôi phục lại:
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 }
};
// Serial hóa thành chuỗi JSON
string json = JsonConvert.SerializeObject(player1, Formatting.Indented);
Console.WriteLine(json);
// Deserialize trả về object Player
Player player2 = JsonConvert.DeserializeObject<Player>(json);
Console.WriteLine($"Tên: {player2.Name}, sức khỏe: {player2.Health}");
Xong? Gần rồi, nhưng đó chỉ là phần nổi của tảng băng. Ta sẽ xem vì sao Newtonsoft.Json thú vị và linh hoạt hơn các thư viện khác.
3. Format, cài đặt và tham số nâng cao
Khi serial hóa object, bạn có thể lấy chuỗi gọn nhẹ hoặc JSON đẹp, nhiều lựa chọn do các setting điều khiển.
Ví dụ: Các kiểu format khác nhau
// JSON dễ đọc đẹp
string prettyJson = JsonConvert.SerializeObject(player1, Formatting.Indented);
// JSON "minified" gọn nhẹ
string compactJson = JsonConvert.SerializeObject(player1, Formatting.None);
Cấu hình serialize
Nếu cần, truyền JsonSerializerSettings để tinh chỉnh:
var settings = new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore, // Bỏ qua các trường có giá trị null
DefaultValueHandling = DefaultValueHandling.Ignore, // Bỏ qua các trường có giá trị mặc định
Formatting = Formatting.Indented
};
string customJson = JsonConvert.SerializeObject(player1, settings);
Bạn có toàn quyền kiểm soát đầu ra: muốn bỏ field rỗng thì có thể, cần serialize cả property private thì cấu hình contract.
4. Điều khiển fields và properties bằng attribute
Newtonsoft.Json hỗ trợ hệ thống attribute mạnh mẽ để tinh chỉnh serialization ngay trong class.
JsonProperty — Đổi tên property
Nếu protocol JSON yêu cầu tên field khác:
public class Player
{
[JsonProperty("player_name")]
public string Name { get; set; }
// ...
}
JSON kết quả:
{ "player_name": "Aragorn", ... }
JsonIgnore — Bỏ qua property
public class Player
{
[JsonIgnore]
public int Health { get; set; }
}
Bây giờ trường Health sẽ biến mất khi serialize.
JsonConverter — Chuyển đổi tuỳ chỉnh
Cho phép chỉ định converter để xử lý một field cụ thể.
public class Player
{
[JsonConverter(typeof(InventoryToStringConverter))]
public List<string> Inventory { get; set; }
}
(Chi tiết về converters — ở phần dưới.)
5. Làm việc với object lồng nhau và collection
Json.NET xử lý tốt object lồng nhau, mảng, collection, dictionary.
Ví dụ: Dictionary
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 sẽ trông như sau:
{
"Scores": {
"Alice": 1023,
"Bob": 999
}
}
6. Cấu trúc phức tạp: liên kết vòng, Self-Referencing Objects
Đôi khi object tham chiếu lẫn nhau. Newtonsoft.Json hỗ trợ serialize những cấu trúc như vậy bằng các setting đặc biệt.
Ví dụ: Giải quyết vòng tham chiếu
public class Person
{
public string Name { get; set; }
public Person Parent { get; set; }
public List<Person> Children { get; set; }
}
// Cấu hình serialize cho vòng tham chiếu
var settings = new JsonSerializerSettings
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore // hoặc .Serialize
};
Person p1 = new Person { Name = "Bố" };
Person p2 = new Person { Name = "Con", Parent = p1 };
p1.Children = new List<Person> { p2 };
string json = JsonConvert.SerializeObject(p1, settings);
Console.WriteLine(json);
Mặc định, nếu để ReferenceLoopHandling = Error, bạn sẽ nhận được exception. Cái này ngăn chặn việc serialize vô hạn.
7. Làm việc với cấu trúc động: JObject, JArray
Khi cấu trúc JSON không biết trước hoặc thay đổi linh hoạt, dùng object động thay vì kiểu tĩnh C#.
Các kiểu chính:
- JObject — đại diện cho JSON object.
- JArray — đại diện cho mảng.
using Newtonsoft.Json.Linq;
// Chuyển chuỗi thành JObject
string json = @"{ 'name': 'Aragorn', 'health': 100 }";
JObject obj = JObject.Parse(json);
Console.WriteLine((string)obj["name"]); // Aragorn
Console.WriteLine((int)obj["health"]); // 100
// Thêm property động
obj["class"] = "Ranger";
Console.WriteLine(obj.ToString());
Duyệt mảng
string jsonArr = @"['apple', 'banana', 'cherry']";
JArray array = JArray.Parse(jsonArr);
foreach (JToken item in array)
{
Console.WriteLine(item);
}
8. Hỗ trợ versioning và trường bắt buộc
Format JSON có thể thay đổi, field có thể mất. Dùng attribute và setting như sau:
- [JsonProperty(Required = Required.Always)] — yêu cầu field phải có (nếu không sẽ ném exception).
- [JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)] — gán giá trị mặc định nếu field không có.
public class Player
{
[JsonProperty(Required = Required.Always)]
public string Name { get; set; }
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
[DefaultValue(50)]
public int Health { get; set; }
}
9. Chuyển đổi ngày và format thời gian
Làm việc với ngày thường cần format rõ ràng.
var dateSettings = new JsonSerializerSettings
{
DateFormatString = "yyyy-MM-dd"
};
string json = JsonConvert.SerializeObject(DateTime.Now, dateSettings);
Console.WriteLine(json); // "2024-06-15"
Và ngược lại khi deserialize:
string dateJson = "\"2024-06-15\""; // Lưu ý: đây là một chuỗi trong dấu ngoặc kép!
DateTime dt = JsonConvert.DeserializeObject<DateTime>(dateJson);
Console.WriteLine(dt);
GO TO FULL VERSION