Skip to content

Serialization in C# — Complete Guide

DodaTech Updated 2026-06-28 5 min read

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

  1. Ignoring case sensitivity: JSON property matching is case-sensitive by default. Set PropertyNameCaseInsensitive = true for flexible deserialization.

  2. Serializing circular references: Object graphs with cycles cause exceptions. Use ReferenceHandler.IgnoreCycles or ReferenceHandler.Preserve.

  3. Forgetting [JsonIgnore] on computed properties: Properties that derive values should be excluded to reduce payload size.

  4. Using Newtonsoft.Json in new projects: System.Text.Json is the modern, recommended serializer. Only use Newtonsoft.Json for legacy compatibility.

  5. Not handling null values: By default, null properties are serialized. Use DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull to omit them.

Practice Questions

  1. Serialize a Dictionary<string, int> to JSON and deserialize it back.

  2. Create a custom JsonConverter that formats a DateTime as "yyyy-MM-dd" during serialization.

  3. Write a program that reads a JSON array from a file, deserializes it to a list of objects, and displays the count.

  4. Challenge: Implement a polymorphic serializer that handles a base class with multiple derived types using a discriminator property.

FAQ

What is the difference between System.Text.Json and Newtonsoft.Json?

System.Text.Json is the official .NET library optimized for performance and reduced allocations. Newtonsoft.Json (Json.NET) has more features like flexible JSON paths and broader type support. For new projects, prefer System.Text.Json.

How do I handle large JSON files?

Use Utf8JsonReader and Utf8JsonWriter for streaming JSON processing, or JsonSerializer.DeserializeAsyncEnumerable for arrays.

Can I serialize properties with private setters?

Yes, in System.Text.Json you can use [JsonInclude] or configure IncludeFields. For JsonSerializerOptions, set IncludeFields = true.

Is JSON serialization thread-safe?

Yes, JsonSerializer is thread-safe. You can cache and reuse serializer options and context instances.

How do I deserialize without knowing the type at compile time?

Use JsonSerializer.Deserialize with object return type, or use JsonDocument / JsonNode for dynamic access.

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