Serialization in C#

Serialization in C# is the process of converting an object into a format that can be stored, transmitted, or reconstructed later. Deserialization is the reverse process, where that stored representation is converted back into an object.

This topic is important because real applications constantly move data between memory, files, databases, APIs, caches, queues, and external systems. Serialization makes that movement possible by transforming object graphs into stable formats such as JSON or XML.

Understanding serialization properly means more than just calling one API method. It also involves knowing what format to choose, how object properties are mapped, how versioning affects data, what attributes can customize behavior, and which older approaches should be avoided in modern C# development.


What Is Serialization in C#?

Serialization converts an object into a transportable representation such as text or bytes. Deserialization reconstructs the object from that representation.

For example, a Student object in memory can be serialized into JSON and saved in a file or returned from an API. Later, the same JSON can be deserialized back into a Student object.

Why Serialization Is Important

Serialization is used in web APIs, configuration systems, caching, messaging systems, local file storage, background processing, and inter-service communication. Without serialization, in-memory object models would remain trapped inside one running process.

It also creates a contract between systems. Once data is serialized into a shared format, another process, service, or application can consume it even if the original in-memory object no longer exists.

Common Serialization Formats in C#

FormatTypical Use
JSONAPIs, config, file storage, messaging
XMLLegacy systems, configuration, integrations
BinaryRaw compact storage in controlled scenarios

In modern C# projects, JSON is the most common format because it is lightweight, widely supported, and easy to exchange between systems.

JSON Serialization with System.Text.Json

The standard modern JSON library in .NET is System.Text.Json. It provides fast, built-in APIs for serializing and deserializing objects.

using System.Text.Json;

public class Student
{
    public string Name { get; set; }
    public int Marks { get; set; }
}

Student student = new Student
{
    Name = "Aarav",
    Marks = 90
};

string json = JsonSerializer.Serialize(student);
Console.WriteLine(json);

This produces a JSON string representation of the object. The serializer maps public properties into JSON fields by default.

Deserializing JSON in C#

To rebuild the object from JSON, use JsonSerializer.Deserialize<T>().

string jsonText = "{\"Name\":\"Diya\",\"Marks\":95}";
Student student = JsonSerializer.Deserialize<Student>(jsonText);

The generic type parameter tells the serializer what object type should be reconstructed from the input JSON.

Serializing Collections

Serialization works not only for single objects but also for lists and other collections.

List<Student> students = new List<Student>
{
    new Student { Name = "Aarav", Marks = 90 },
    new Student { Name = "Diya", Marks = 95 }
};

string json = JsonSerializer.Serialize(students);

This is especially common in APIs and file-based data storage where arrays of objects must be written and read together.

Formatting JSON Output

For debugging, configuration files, or human-readable outputs, you may want pretty-printed JSON instead of a compact single line.

var options = new JsonSerializerOptions
{
    WriteIndented = true
};

string prettyJson = JsonSerializer.Serialize(student, options);

This does not change the underlying data, only the formatting of the serialized output.

Customizing Property Names

Sometimes the JSON property name should differ from the C# property name. Attributes can be used to customize this mapping.

using System.Text.Json.Serialization;

public class Student
{
    [JsonPropertyName("student_name")]
    public string Name { get; set; }
}

This is useful when matching an external API contract or a stored data format that uses different naming conventions.

Ignoring Properties During Serialization

If certain properties should not be included in the output, the JsonIgnore attribute can be used.

public class User
{
    public string Username { get; set; }

    [JsonIgnore]
    public string Password { get; set; }
}

This is important for hiding sensitive information or avoiding values that should stay internal to the running process.

Serialization Options in C#

JsonSerializerOptions provides many useful settings such as case handling, indentation, and property naming policies.

var options = new JsonSerializerOptions
{
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
    WriteIndented = true
};

This matters because many APIs expect camelCase JSON even when C# property names use PascalCase.

Serialization to and from Files

One common use of serialization is saving objects to a file and reading them back later.

string json = JsonSerializer.Serialize(student, options);
File.WriteAllText("student.json", json);

string jsonFromFile = File.ReadAllText("student.json");
Student loadedStudent = JsonSerializer.Deserialize<Student>(jsonFromFile);

This pattern is useful for local persistence, exports, configuration snapshots, and lightweight storage scenarios.

XML Serialization in C#

Although JSON is dominant in many modern systems, XML serialization still matters in legacy applications and certain integrations.

using System.Xml.Serialization;

XmlSerializer serializer = new XmlSerializer(typeof(Student));

XML is often more verbose than JSON, but it is still used in older enterprise systems, specific protocols, and some document-like data exchanges.

Binary Serialization in Modern C#

Older .NET examples often mention binary serialization. In modern C# development, the old BinaryFormatter approach is considered unsafe and should be avoided for most scenarios. Modern applications should prefer safer formats and serializers such as JSON unless there is a very specific controlled requirement for raw binary handling.

This is an important practical point because many outdated tutorials still present obsolete binary serialization patterns without emphasizing the security risk.

Serialization and Versioning

Serialized data often outlives one version of the code. That means object models may evolve while old serialized data still exists in files, caches, or external systems. Versioning concerns include renamed properties, removed fields, added fields, or changed data formats.

Good serialization design tries to evolve contracts carefully. Breaking changes in serialized data can affect backward compatibility and lead to runtime failures when old and new systems interact.

Serialization and Security

Serialization always deserves security attention. You should not blindly trust incoming serialized data from untrusted sources. Deserialized objects may contain invalid, malicious, or unexpected values. Validation still matters after deserialization.

This also applies to data exposure. If an object contains secrets, internal IDs, or fields that should not leave the service boundary, those fields must be excluded or mapped carefully before serialization.

Common Mistakes with Serialization

  • Assuming every property should always be serialized.
  • Ignoring naming conventions required by external APIs.
  • Using obsolete binary serialization approaches from outdated tutorials.
  • Deserializing untrusted data without validation.
  • Forgetting that data contracts may need versioning support over time.

These issues matter because serialization sits directly on the boundary between your application and external storage or communication systems.

Best Practices for Serialization in C#

  • Prefer System.Text.Json for modern JSON serialization unless another library is specifically required.
  • Use attributes and options to match the required external data contract clearly.
  • Exclude sensitive or irrelevant properties from serialized output.
  • Validate deserialized input instead of assuming the data is trustworthy.
  • Think about backward compatibility when serialized data may persist across versions.

Serialization in Real Applications

In real applications, serialization is used for API requests and responses, config files, background message payloads, cache entries, export files, inter-service communication, and audit snapshots. It is one of the most common infrastructure concerns in modern software systems.

That is why serialization should be understood as a boundary design topic, not just a syntax topic. It affects compatibility, performance, security, and maintainability all at once.

Serialization Interview Points

For interviews, remember that serialization converts objects into transportable formats and deserialization reconstructs them. You should know JSON serialization with System.Text.Json, XML serialization basics, customization with attributes, and why old BinaryFormatter-style approaches are avoided in modern code.

A stronger answer also mentions versioning, security considerations, and the fact that serialization is commonly used at service and storage boundaries.

FAQs on Serialization in C#

What is serialization in C#?

Serialization in C# is the process of converting an object into a storable or transferable format such as JSON or XML.

What is deserialization in C#?

Deserialization is the reverse process of rebuilding an object from serialized data.

Which library is commonly used for JSON serialization in modern C#?

System.Text.Json is the standard built-in choice in modern .NET applications.

Why should old BinaryFormatter-style serialization be avoided?

It is considered unsafe and obsolete for most modern scenarios, so safer formats such as JSON are preferred.

Serialization of Nested Objects

Real objects often contain other objects or collections, not just primitive values. Modern serializers handle nested structures naturally as long as the object model is serializable through public properties or configured access rules.

public class Address
{
    public string City { get; set; }
    public string Country { get; set; }
}

public class Student
{
    public string Name { get; set; }
    public Address Address { get; set; }
}

This matters because serialization is rarely limited to flat objects in real systems. Nested models are the normal case in APIs and persistence scenarios.

Serialization and DTO Design

In many applications, the object being serialized is not the same as the internal domain object. Instead, developers often create DTOs, or Data Transfer Objects, that contain only the fields that should cross the boundary. This keeps serialization contracts clean and reduces accidental exposure of internal fields or business logic concerns.

That separation is important because serialization often represents a public or persisted contract, while internal classes may evolve more freely.

Async Serialization Workflows

Serialization also appears in asynchronous workflows, especially when writing to files, HTTP responses, or network streams. In these cases, the application may serialize data and then write it through async I/O to keep the system responsive.

This is common in web APIs, background workers, and services that process large payloads or many requests concurrently.

Null Values and Optional Data

Serialized data often includes optional fields. Some systems want null values preserved, while others prefer them omitted. Serializer options and attributes help control this behavior. Understanding null handling is important because it affects compatibility, payload size, and how consumers interpret missing versus explicitly null data.

This is especially relevant in APIs where the meaning of “not provided” may differ from the meaning of “provided but null.”

Reference Cycles and Complex Graphs

Some object graphs contain cycles, such as parent objects referencing children while children also reference parents. Naive serialization of those graphs can cause problems such as loops or unexpected output. Modern serializers provide configuration options for dealing with reference handling, but the best design sometimes involves shaping the outgoing data into a simpler DTO rather than serializing the full graph directly.

This is a practical design point because direct serialization of rich domain graphs is often more fragile than developers expect.

Polymorphism and Serialization

Serialization becomes more complex when a base type can actually hold multiple derived types. In those cases, extra configuration or metadata may be required so the serializer knows how to represent and reconstruct the correct runtime shape. This is one of the reasons serialization design is not always trivial in advanced object models.

For many systems, the simplest and most reliable approach is to serialize explicit DTOs with stable known shapes instead of exposing deep polymorphic object graphs directly.

Choosing JSON vs XML in Practice

JSON is usually the default in modern services because it is lightweight and widely supported. XML still has a place when working with older enterprise integrations, document-style exchanges, or systems that are already built around XML contracts. The right choice depends less on personal preference and more on the ecosystem your application must communicate with.

This is why serialization format decisions are often integration decisions rather than purely language-level decisions.

That makes serialization a design concern as much as a coding task.