CodeGym /Các khóa học /C# SELF /Thảo luận BinaryFormatter<...

Thảo luận BinaryFormatter

C# SELF
Mức độ , Bài học
Có sẵn

1. Giới thiệu

Trong nhiều sách và ví dụ cũ về C# bạn có thể gặp serialization bằng lớp BinaryFormatter. Ngày trước đây nó là tiêu chuẩn: tiện, nhanh, bớt lo nghĩ. Ví dụ từ thời xưa trông khoảng như sau:

// Opasnyy staryy kod! Ne delayte tak v novykh proektakh!
var bf = new BinaryFormatter();
using (var stream = File.Open("player.dat", FileMode.Create))
{
    bf.Serialize(stream, playerObject);
}

Nhưng trong .NET 9 hiện đại bạn thậm chí sẽ không thể biên dịch đoạn mã như vậy: BinaryFormatter đã bị xóa khỏi nền tảng.

Con đường từ anh hùng tới kẻ bị ruồng bỏ

Ban đầu BinaryFormatter được thiết kế như một cơ chế universal để serialize và deserialize các đối tượng .NET, có thể lưu các đồ thị đối tượng phức tạp "nguyên trạng". Theo thời gian lộ ra những vấn đề nghiêm trọng về bảo mật và tương thích, và giờ nó trở thành quá khứ — giống như đầu cassette thời streaming.

2. Những lý do chính để từ bỏ BinaryFormatter

Lỗ hổng bảo mật khổng lồ

BinaryFormatter không chỉ serialize dữ liệu mà còn có thể phục hồi kiểu từ luồng vào. Nếu deserialize dữ liệu không kiểm tra (ví dụ nhận từ mạng), attacker có thể chèn payload gây thực thi mã từ xa (RCE). Vì vậy Microsoft nhiều năm cảnh báo: "Ne ispol'zuyte BinaryFormatter". Bắt đầu từ .NET 5 nó bị đánh dấu là deprecated và nguy hiểm ([Obsolete]), còn trong .NET 9 — bị xóa.

Phụ thuộc vào cấu trúc nội bộ lớp

Định dạng của BinaryFormatter kéo theo chi tiết hiện thực của type: fields, boxing, versioning. Thay đổi nhỏ trong class (thêm/bớt field) phá vỡ tương thích với file đã lưu. Điều này làm định dạng không phù hợp cho lưu trữ lâu dài hoặc trao đổi giữa các phiên bản.

Khó khăn về cross-platform

Dữ liệu lưu bằng BinaryFormatter gắn với biểu diễn nội bộ của object .NET. Đọc chúng trên nền tảng/ngôn ngữ khác hoặc thậm chí phiên bản .NET khác thường là không thể.

3. Làm sao phát hiện "mã cũ" và phải làm gì?

Dấu hiệu sử dụng BinaryFormatter trông như sau:

using System.Runtime.Serialization.Formatters.Binary; // <-- podozritel'no!
BinaryFormatter bf = new BinaryFormatter();           // <-- opasno!
bf.Serialize(...);
bf.Deserialize(...);

Trong các phiên bản .NET hiện đại đoạn mã này không biên dịch: tooling sẽ báo lỗi "Tip ili imya ne naydeno". Trong các dự án legacy chạy trên .NET Framework — ít nhất sẽ có cảnh báo nghiêm trọng.

Nếu bạn gặp mã như vậy, hãy thay BinaryFormatter bằng các alternative an toàn, hiện đại.

Nên dùng định dạng và lớp nào hôm nay?

Cho JSON

  • System.Text.Json — nhanh, an toàn, tích hợp sẵn trong .NET. Tai lieu chinh thuc
  • Newtonsoft.Json — thư viện bên thứ ba phổ biến cho các case phức tạp.

Cho XML

  • XmlSerializer — serialization sang XML. Tai lieu

Cho định dạng nhị phân

  • System.Formats.Cbor (CBOR)
  • Protobuf.Net (Protocol Buffers), MessagePack for C#

Với các task đặc thù hãy chọn định dạng và thư viện chuyên dụng — không còn "universal" binary serializer kiểu BinaryFormatter nữa, và đó là điều tốt.

4. Viết lại mã thay BinaryFormatter

Những việc không nên dùng BinaryFormatter cho

Không được:

  • Lưu cài đặt người dùng và dữ liệu quan trọng.
  • Truyền dữ liệu qua mạng (client ↔ server).
  • Deserialize dữ liệu từ nguồn không đáng tin cậy.

Thay vào đó:

  • Cho nhu cầu hàng ngày — System.Text.Json.
  • Cho cấu hình — JSON, XML v.v.
  • Cho trao đổi liên ngôn ngữ — định dạng cross-platform (JSON, XML, Protobuf, MessagePack).

Nên viết mã như thế nào bây giờ?

Serialize sang JSON (cách được khuyến nghị)

using System.Text.Json;
// Vash klass:
public class Player
{
    public string Name { get; set; } = "";
    public int Health { get; set; }
    public bool IsAlive { get; set; }
}

// Ob'ekt dlya serializatsii
var player = new Player { Name = "Aragorn", Health = 100, IsAlive = true };

// Preobrazuyem ob'ekt v stroku JSON
string json = JsonSerializer.Serialize(player);

// Sokhranyaem v fajl — bezopasno!
File.WriteAllText("player.json", json);

// Chtoby vosstanovit' ob'ekt iz fajla:
string loadedJson = File.ReadAllText("player.json");
Player loadedPlayer = JsonSerializer.Deserialize<Player>(loadedJson)!;

Serialize sang XML (nếu cần định dạng nghiêm ngặt)

using System.Xml.Serialization;
// Klass dolzhen imet' publichnyy konstruktor bez parametrov

var player = new Player { Name = "Aragorn", Health = 100, IsAlive = true };
var serializer = new XmlSerializer(typeof(Player));
using (var fs = File.Create("player.xml"))
{
    serializer.Serialize(fs, player);
}

Sơ đồ trực quan "cũ vs mới"

Zadacha Staryy sposob (BinaryFormatter) Sovremennyy sposob
Serializatsiya v fajl
bf.Serialize(stream, obj)
JsonSerializer.Serialize(...)
XmlSerializer.Serialize(...)
Deserializatsiya iz fajla
bf.Deserialize(stream)
JsonSerializer.Deserialize<T>(...)
XmlSerializer.Deserialize(...)
Bezopasnost' Uyazvim dlya atak (RCE) Bezopasnye parsery i strogie modeli
Kross-platformennost' Net Da (JSON/XML/Protobuf)
Bystro, no opasno Bystro i bezopasno

5. Lỗi điển hình khi làm việc với XmlSerializer

Oshibka №1: privatnye svoystva ili polya. XmlSerializer serializuyet tol'ko public svoystva; dazhe protected privedyot k oshibke.

Oshibka №2: otsutstvie konstruktora po umolchaniyu. Nuzhen publichnyy konstruktor bez parametrov, inache serialization/deserialization ne srabotaet.

Oshibka №3: nesootvetstvie mezhdu tipami dannykh. XmlSerializer ploho rabotaet s Dictionary, interface i delegate — ispol'zuyte oberty ili drugie formati.

Oshibka №4: ciklicheskie ssylki (circular reference). XmlSerializer ne podderzhivayet grafy vida A → B → A; dlya takikh sluchaev chashche berut JSON s podkhodyashchimi nastrojkami.

2
Nhiệm vụ
C# SELF, mức độ, bài học
Đã khóa
So sánh việc tuần tự hóa JSON và XML cho một đối tượng đơn giản
So sánh việc tuần tự hóa JSON và XML cho một đối tượng đơn giản
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION