Serialization in C# — Complete Guide
In this tutorial, you will learn about Serialization in C#. We cover key concepts, practical examples, and best practices to help you master this topic.
Hook
Serialization is the bridge between in-memory objects and persistent storage or network transmission. Whether you are saving application state, sending data over an API, or Caching results, mastering serialization in C# is essential for building robust applications.
Learning Path
graph LR A[Serialization] --> B[System.Text.Json] A --> C[XML Serialization] A --> D[Binary Serialization] B --> E[JsonSerializer] B --> F[Source Generators] style A fill:#4a90d9,color:#fff style B fill:#4a90d9,color:#fff style C fill:#4a90d9,color:#fff style D fill:#4a90d9,color:#fff style E fill:#4a90d9,color:#fff style F fill:#4a90d9,color:#fff
System.Text.Json
Since .NET Core 3.0, the recommended JSON serializer is System.Text.Json. It is high-performance, allocation-efficient, and built into the .NET runtime.
using System;
using System.Text.Json;
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public string? Email { get; set; }
}
// Serialize
Person person = new Person { Name = "Alice", Age = 30, Email = "alice@example.com" };
string json = JsonSerializer.Serialize(person);
Console.WriteLine(json);
// Deserialize
Person? deserialized = JsonSerializer.Deserialize<Person>(json);
Console.WriteLine($"{deserialized?.Name}, {deserialized?.Age}");
Output:
{"Name":"Alice","Age":30,"Email":"alice@example.com"}
Alice, 30
Customizing JSON Serialization
Use JsonSerializerOptions to control formatting, naming policies, and more.
var options = new JsonSerializerOptions
{
WriteIndented = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
PropertyNameCaseInsensitive = true
};
Person person = new Person { Name = "Bob", Age = 25, Email = null };
string indentedJson = JsonSerializer.Serialize(person, options);
Console.WriteLine(indentedJson);
Person? caseInsensitive = JsonSerializer.Deserialize<Person>(
"{\"name\":\"Charlie\",\"age\":35}", options);
Console.WriteLine($"{caseInsensitive?.Name}");
Output:
{
"name": "Bob",
"age": 25
}
Charlie
Handling Enums and Custom Converters
public enum Status { Active, Inactive, Pending }
public class Order
{
public int Id { get; set; }
public Status Status { get; set; }
}
var order = new Order { Id = 1, Status = Status.Active };
// Enum as string
var options = new JsonSerializerOptions
{
Converters = { new JsonStringEnumConverter() }
};
string json = JsonSerializer.Serialize(order, options);
Console.WriteLine(json);
Order? restored = JsonSerializer.Deserialize<Order>(json, options);
Console.WriteLine($"Status: {restored?.Status}");
Output:
{"Id":1,"Status":"Active"}
Status: Active
JSON Source Generators
For optimal performance and trimming support, use source-generated serialization.
using System.Text.Json.Serialization;
[JsonSerializable(typeof(Person))]
[JsonSerializable(typeof(List<Person>))]
internal partial class AppJsonContext : JsonSerializerContext { }
// Usage
Person person = new Person { Name = "Diana", Age = 28 };
string json = JsonSerializer.Serialize(person, AppJsonContext.Default.Person);
Console.WriteLine(json);
Source generators eliminate runtime Reflection and improve startup time significantly.
XML Serialization
XML serialization uses System.Xml.Serialization.XmlSerializer.
using System.Xml.Serialization;
public class Book
{
[XmlAttribute]
public string Isbn { get; set; }
public string Title { get; set; }
[XmlElement("Author")]
public string AuthorName { get; set; }
[XmlIgnore]
public int InternalId { get; set; }
}
Book book = new Book
{
Isbn = "978-3-16-148410-0",
Title = "C# Programming",
AuthorName = "John Doe",
InternalId = 99
};
XmlSerializer serializer = new XmlSerializer(typeof(Book));
using (StringWriter writer = new StringWriter())
{
serializer.Serialize(writer, book);
Console.WriteLine(writer.ToString());
}
Output:
<?xml version="1.0" encoding="utf-16"?>
<Book xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Isbn="978-3-16-148410-0">
<Title>C# Programming</Title>
<Author>John Doe</Author>
</Book>
Data Contract Serialization
For WCF-style serialization, use DataContractSerializer.
using System.Runtime.Serialization;
[DataContract]
public class Employee
{
[DataMember]
public string Name { get; set; }
[DataMember(Name = "employee_id")]
public int Id { get; set; }
[IgnoreDataMember]
public string? TempData { get; set; }
}
Common Mistakes
Ignoring case sensitivity: JSON property matching is case-sensitive by default. Set
PropertyNameCaseInsensitive = truefor flexible deserialization.Serializing circular references: Object graphs with cycles cause exceptions. Use
ReferenceHandler.IgnoreCyclesorReferenceHandler.Preserve.Forgetting [JsonIgnore] on computed properties: Properties that derive values should be excluded to reduce payload size.
Using Newtonsoft.Json in new projects:
System.Text.Jsonis the modern, recommended serializer. Only use Newtonsoft.Json for legacy compatibility.Not handling null values: By default, null properties are serialized. Use
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNullto omit them.
Practice Questions
Serialize a
Dictionary<string, int>to JSON and deserialize it back.Create a custom
JsonConverterthat formats aDateTimeas "yyyy-MM-dd" during serialization.Write a program that reads a JSON array from a file, deserializes it to a list of objects, and displays the count.
Challenge: Implement a polymorphic serializer that handles a base class with multiple derived types using a discriminator property.
FAQ
Mini Project: Configuration Loader
Create a configuration loader that reads settings from a JSON file and maps them to a strongly-typed Settings class.
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
public class Settings
{
public string DatabaseConnectionString { get; set; } = "";
public int MaxRetryCount { get; set; } = 3;
public bool EnableLogging { get; set; } = true;
public List<string> AllowedHosts { get; set; } = new();
}
string configPath = "appsettings.json";
// Default config
var defaultSettings = new Settings
{
DatabaseConnectionString = "Server=localhost;Database=app",
MaxRetryCount = 5,
EnableLogging = true,
AllowedHosts = new() { "localhost", "example.com" }
};
string json = JsonSerializer.Serialize(defaultSettings,
new JsonSerializerOptions { WriteIndented = true });
File.WriteAllText(configPath, json);
// Load and validate
string loadedJson = File.ReadAllText(configPath);
Settings? settings = JsonSerializer.Deserialize<Settings>(loadedJson);
Console.WriteLine($"Connection: {settings?.DatabaseConnectionString}");
Console.WriteLine($"Retries: {settings?.MaxRetryCount}");
Console.WriteLine($"Logging: {settings?.EnableLogging}");
Console.WriteLine($"Hosts: {string.Join(", ", settings?.AllowedHosts ?? new())}");
Output:
Connection: Server=localhost;Database=app
Retries: 5
Logging: True
Hosts: localhost, example.com
This project demonstrates how serialization bridges configuration files and strongly-typed objects, a common pattern in .NET applications.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro