1. Introduction
Since we decided to "disassemble a LEGO figure into parts", let's figure out what tools we have in .NET for that. In other words — which standard classes help serialize and deserialize objects into different formats and what's behind each of them.
How the .NET serialization family is organized
At the moment (2025) .NET offers several main approaches to serialization, each with its own set of classes and tools. The main and most commonly encountered ones:
- JSON serialization — the main and most modern option, used in most projects.
- XML serialization — a bit old-fashioned, but still actively used.
- Binary serialization — only for special cases and usually via modern third-party solutions.
Many examples and the majority of code in .NET 9 use JSON, and that's not a fad — it's an industry standard. But .NET supports other ways too — just in case.
Main players of .NET serialization
| Format | Serialization class | Ease | Performance | Security | Relevance |
|---|---|---|---|---|---|
| JSON | |
🔥🔥🔥 | 🔥🔥🔥 | 🔥🔥🔥 | Most relevant |
| XML | |
🔥🔥 | 🔥🔥 | 🔥🔥 | Used |
| JSON | Newtonsoft.Json (Json.NET) | 🔥🔥🔥 | 🔥🔥 | 🔥🔥🔥 | Very popular |
Short about each
- System.Text.Json: The new standard for JSON serialization in .NET, introduced in .NET Core 3.0, became the main one in .NET 5+. Fast, lightweight, safe, built-in "out of the box" in .NET 9. Documentation
- XmlSerializer: An old and proven option for XML serialization. Simple to use, but with limitations (for example, it requires a public class and public properties). Good for compatibility and strict data contracts. Documentation
- Newtonsoft.Json: For a long time it was the de-facto standard for JSON serialization before System.Text.Json appeared. Often used for complex scenarios (dynamics, private properties, etc.). Documentation
Where did BinaryFormatter go?
If you see advice on the internet to use BinaryFormatter — it's probably an ancient tutorial. Don't use BinaryFormatter: it was removed from .NET 9 for security reasons. Modern binary serialization is provided by third-party solutions — for example, Protobuf or MessagePack.
2. Simple examples
Let's try serialization and deserialization in practice using our already familiar class Player from the game universe.
Prepare the class for serialization
// Player.cs
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; }
}
a) JSON serialization and deserialization with System.Text.Json
using System.Text.Json;
Player aragorn = new Player
{
Name = "Aragorn",
Health = 100,
IsAlive = true,
Inventory = new List<string> { "sword", "bow", "healing potion" },
Position = new Position { X = 10, Y = 25 }
};
// Serialize the Player object to a JSON string
string json = JsonSerializer.Serialize(aragorn);
// Print JSON to the screen
Console.WriteLine(json);
// Deserialize the JSON string back to a Player object
Player? aragornClone = JsonSerializer.Deserialize<Player>(json);
// Check that the clone works :)
Console.WriteLine(aragornClone?.Name); // Should print "Aragorn"
It's that simple — no "dance with a tambourine" or magical attributes. Now — how it looks in XML.
b) XML serialization and deserialization with XmlSerializer
using System.Xml.Serialization;
// Configure the serializer for the Player class
XmlSerializer serializer = new XmlSerializer(typeof(Player));
// Serialize to a file
using FileStream fs = new FileStream("aragorn.xml", FileMode.Create);
serializer.Serialize(fs, aragorn); // Save Aragorn to an XML file
// Deserialize from a file
using FileStream fs = new FileStream("aragorn.xml", FileMode.Open);
Player aragornFromXml = (Player) serializer.Deserialize(fs)!;
Console.WriteLine(aragornFromXml.Name); // Should print "Aragorn"
Note! XmlSerializer requires that classes and their properties are public and have a parameterless default constructor (if you override the constructor — make it public and parameterless). Otherwise serialization will fail.
c) JSON serialization and deserialization with Newtonsoft.Json
using Newtonsoft.Json; // Don't forget to add the Newtonsoft.Json package via NuGet!
// Serialization
string json2 = JsonConvert.SerializeObject(aragorn);
// Deserialization
Player? aragornFromNewtonsoft = JsonConvert.DeserializeObject<Player>(json2);
Console.WriteLine(aragornFromNewtonsoft?.Name); // Again "Aragorn"
Looks almost the same, but Newtonsoft.Json has many extra options — for example, you can serialize private fields, customize formatting and handle non-trivial scenarios.
4. Useful nuances
Standard serializers and their capabilities
| Class | Format | Built into .NET | Requires NuGet package? | Good for files | Good for APIs | Ease |
|---|---|---|---|---|---|---|
|
JSON | Yes | No | Yes | Yes | Lightweight |
|
JSON | No | Yes | Yes | Yes | Lightweight |
|
XML | Yes | No | Yes | Often | Lightweight |
How to decide which class to use?
If you don't know why you need XML — almost always choose JSON and System.Text.Json. It's faster, simpler and matches modern practices.
Choose XML if:
- You're integrating with legacy systems that require XML.
- You need a strict schema and validation of the data structure.
- Structures are large, stable and formal compatibility matters (settings, configs, exchange with enterprise systems).
Choose JSON if:
- You're building a modern app interacting with web and mobile clients.
- You need simplicity, readability and compactness.
- You don't want to pull in extra dependencies.
Choose Newtonsoft.Json if:
- You need serialization of private fields, special customizations, full flexibility.
- Or the project already inherited this library and migration is not practical right now.
5. Common mistakes and pitfalls
Encoding. The main serialization classes (especially when working with files) use UTF-8 by default. If you see garbled characters, check how you're reading/writing files and the explicit encoding settings. Documentation on encoding configuration.
Unsupported types. Some standard serializers (especially XML) can't serialize, for example, dictionaries (Dictionary), private/protected fields, events, delegates and interfaces. Usually public simple properties and classes are supported.
Class versions. If you change class structure (added/renamed/removed properties), old saved data may not read or may deserialize incorrectly. Plan for format versioning.
Null values. When deserializing, if some field is missing in the data, the corresponding property will get the default value (for reference types — null). Don't forget to add checks.
Attributes. For precise control people often use attributes like [JsonIgnore], [XmlElement] and others. They let you exclude properties, change element names and manage format — details in following lectures.
GO TO FULL VERSION