CodeGym /Courses /C# SELF /Using Newtonsoft.Json

Using Newtonsoft.Json

C# SELF
Level 44, Lesson 4
Available

1. Introduction

Newtonsoft.Json is kind of a dinosaur in a good way. It was the de-facto standard for working with JSON in the .NET ecosystem for years, long before System.Text.Json even existed. Millions of projects, thousands of libraries and frameworks (even many parts of ASP.NET Core until recently) used Json.NET.

Its advantages are that it:

  • Is feature-rich and flexible: Json.NET offers a huge number of settings, attributes and customization points for the serialization/deserialization process. It can do things that System.Text.Json either struggles with or can't do at all.
  • Is tolerant of "imperfect" JSON: data from external systems isn't always ideal — Json.NET is often more forgiving and lets you deserialize without extra pain.
  • Is backwards compatible: if a project or library depends on Json.NET, knowing how to work with it remains necessary.

Of course, System.Text.Json is faster and built with modern requirements in mind. But Newtonsoft.Json is still a powerful tool, especially when you need specific logic or maximum flexibility.

How to install Newtonsoft.Json?

Since it's a third-party library, add the package via NuGet:

  1. Open the project.
  2. Right-click the project in Solution Explorer.
  3. Choose "Manage NuGet Packages...".
  4. In the search box type Newtonsoft.Json.
  5. Select the package and click "Install".

After installation you'll have a new dependency — you can use Json.NET!

Feature comparison: Newtonsoft.Json vs System.Text.Json

Feature System.Text.Json Newtonsoft.Json
Simple serialization/deserialization Yes Yes
Support for property attributes Partially Full
Custom converters Yes Yes
Working with private fields No Yes
Working with dynamic structures Limited Yes
LINQ to JSON (JObject/JArray) No Yes
Reference Loop Handling Yes Yes
Support for DataTable, DataSet and complex types No Yes
Performance Better Good

2. Example of serializing and deserializing a simple object

Let's take a common game structure that evolves across lectures:

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; }
}

Now let's save a Player object to JSON and restore it:

using Newtonsoft.Json;

Player player1 = new Player
{
    Name = "Aragorn",
    Health = 100,
    IsAlive = true,
    Inventory = new List<string> { "sword", "bow", "healing potion" },
    Position = new Position { X = 10, Y = 25 }
};

// Serialize to a JSON string
string json = JsonConvert.SerializeObject(player1, Formatting.Indented);
Console.WriteLine(json);

// Deserialize back to a Player object
Player player2 = JsonConvert.DeserializeObject<Player>(json);
Console.WriteLine($"Name: {player2.Name}, health: {player2.Health}");

Everything? Almost, but that's just the tip of the iceberg. Let's explore why Newtonsoft.Json is more interesting and flexible than other libraries.

3. Formatting, settings and advanced options

When you serialize an object you can get either a compact string or nicely formatted JSON. The behavior is controlled by options and settings.

Example: Different formatting options

// Pretty readable JSON
string prettyJson = JsonConvert.SerializeObject(player1, Formatting.Indented);

// Compact "minified" JSON
string compactJson = JsonConvert.SerializeObject(player1, Formatting.None);

Serialization settings

If needed, pass JsonSerializerSettings for fine control:

var settings = new JsonSerializerSettings
{
    NullValueHandling = NullValueHandling.Ignore, // Skip fields with null
    DefaultValueHandling = DefaultValueHandling.Ignore, // Skip default-valued fields
    Formatting = Formatting.Indented
};
string customJson = JsonConvert.SerializeObject(player1, settings);

You get maximum control over the output format: want to skip empty fields — go ahead. Need to serialize even private properties — configure the contract.

4. Controlling fields and properties with attributes

Newtonsoft.Json supports a powerful attribute system that configures serialization right in the class.

JsonProperty — Renaming properties

If the JSON protocol requires a different field name:

public class Player
{
    [JsonProperty("player_name")]
    public string Name { get; set; }
    // ...
}

Resulting JSON:

{ "player_name": "Aragorn", ... }

JsonIgnore — Ignore a property

public class Player
{
    [JsonIgnore]
    public int Health { get; set; }
}

Now the Health field will disappear during serialization.

JsonConverter — Custom conversions

Allows specifying which converter should handle a specific field.

public class Player
{
    [JsonConverter(typeof(InventoryToStringConverter))]
    public List<string> Inventory { get; set; }
}

(More about converters below.)

5. Working with nested objects and collections

Json.NET handles nested objects, arrays, collections and dictionaries very well.

Example: Dictionaries

public class GameStats
{
    public Dictionary<string, int> Scores { get; set; }
}

GameStats stats = new GameStats
{
    Scores = new Dictionary<string, int>
    {
        ["Alice"] = 1023,
        ["Bob"] = 999
    }
};

string statsJson = JsonConvert.SerializeObject(stats, Formatting.Indented);
Console.WriteLine(statsJson);

The JSON will look like this:

{
  "Scores": {
    "Alice": 1023,
    "Bob": 999
  }
}

6. Complex structures: cyclic references, Self-Referencing Objects

Sometimes objects reference each other. Newtonsoft.Json supports serializing such structures via special settings.

Example: Resolving cyclic references

public class Person
{
    public string Name { get; set; }
    public Person Parent { get; set; }
    public List<Person> Children { get; set; }
}

// Configure serialization for cycles
var settings = new JsonSerializerSettings
{
    ReferenceLoopHandling = ReferenceLoopHandling.Ignore // or .Serialize
};

Person p1 = new Person { Name = "Papa" };
Person p2 = new Person { Name = "Son", Parent = p1 };
p1.Children = new List<Person> { p2 };

string json = JsonConvert.SerializeObject(p1, settings);
Console.WriteLine(json);

By default, if you leave ReferenceLoopHandling = Error, you'll get an exception. This protects from accidental infinite serialization.

7. Working with dynamic structures: JObject, JArray

When the JSON structure is unknown in advance or changes on the fly, use dynamic objects without strict C# typing.

Main types:

  • JObject — representation of a JSON object.
  • JArray — representation of an array.
using Newtonsoft.Json.Linq;

// Convert a string to a JObject
string json = @"{ 'name': 'Aragorn', 'health': 100 }";
JObject obj = JObject.Parse(json);

Console.WriteLine((string)obj["name"]); // Aragorn
Console.WriteLine((int)obj["health"]);  // 100

// Dynamically add properties
obj["class"] = "Ranger";
Console.WriteLine(obj.ToString());

Iterating over an array

string jsonArr = @"['apple', 'banana', 'cherry']";
JArray array = JArray.Parse(jsonArr);

foreach (JToken item in array)
{
    Console.WriteLine(item);
}

8. Versioning support and required fields

JSON schema can change, fields may be missing. Use attributes and settings:

  • [JsonProperty(Required = Required.Always)] — require a field to be present (otherwise an exception).
  • [JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)] — populate default if the field is missing.
public class Player
{
    [JsonProperty(Required = Required.Always)]
    public string Name { get; set; }

    [JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
    [DefaultValue(50)]
    public int Health { get; set; }
}

9. Date and time formatting

Working with dates often requires an explicit format.

var dateSettings = new JsonSerializerSettings
{
    DateFormatString = "yyyy-MM-dd"
};
string json = JsonConvert.SerializeObject(DateTime.Now, dateSettings);
Console.WriteLine(json); // "2024-06-15"

And back when deserializing:

string dateJson = "\"2024-06-15\""; // Note: this is a quoted string!
DateTime dt = JsonConvert.DeserializeObject<DateTime>(dateJson);
Console.WriteLine(dt);
2
Task
C# SELF, level 44, lesson 4
Locked
Using JsonProperty and JsonIgnore Attributes
Using JsonProperty and JsonIgnore Attributes
1
Survey/quiz
Standard Serialization Classes, level 44, lesson 4
Unavailable
Standard Serialization Classes
Classes and libraries for serialization
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION