Migrate from Newtonsoft.Json to System.Text.Json - .NET

Working with JSON in .NET: A Comprehensive Guide

Every developer must have used JSON in their life. Json.NET was the library that Microsoft used in their every framework from Mobile to Web. Now Microsoft has released their own library for JSON that is written from scratch and is highly performant. In this article, we will explore the new JSON API provided by Microsoft.

Table of Contents

Serialize POCO to JSON

Let’s start with a basic example. Consider the following code snippet where we are serializing a POCO (Plain Old CLR Object) class to JSON:

void Main()
{

	var response = new ResponseJson
	{
		Status = true,
		Message = "my message",
		LogId = "my log id",
		LogStatus = "my log status"
	};


	var json = JsonSerializer.Serialize(response);

	Console.WriteLine("Serialized {0}", response);
	Console.WriteLine(json);
}

public class ResponseJson
{
	public bool Status { get; set; }
	public string Message { get; set; }
	public string LogId { get; set; }
	public string LogStatus { get; set; }

}

Serialized ResponseJson
{"Status":true,"Message":"my message","LogId":"my log id","LogStatus":"my log status"}

Customize property names

By default, the JSON property name is the same as the C# property name. If you want to control the name of the JSON property, you can use the JsonPropertyName attribute as shown below:

public class ResponseJson
{
	[JsonPropertyName("status")]
	public bool Status { get; set; }
	[JsonPropertyName("message")]
	public string Message { get; set; }
	[JsonPropertyName("Log_id")]
	public string LogId { get; set; }
	[JsonPropertyName("Log_status")]
	public string LogStatus { get; set; }
	
}

output

Serialized ResponseJson
{"status":true,"message":"my message","Log_id":"my log id","Log_status":"my log status"}

How to Deserialize JSON to POCO

To deserialize JSON into a POCO class, you can use the JsonSerializer.Deserialize method. Here’s an example:

{
   "status":true,
   "message":"my message",
   "Log_id":"my log id",
   "Log_status":"my log status"
}

void Main()
{
    var jsonResponse="{\"Status\":true,\"Message\":\"my message\",\"LogId\":\"my log id\",\"LogStatus\":\"my log status\"}";
	var json = JsonSerializer.Deserialize<ResponseJson>(jsonResponse);
	Console.WriteLine("Serialized {0}", json);
	Console.WriteLine(json);
}

How to print Indented JSON

If you want to print indented JSON output, then you can pass JsonSerializerOptions and set the property WriteIndented=true

void Main()
{
	var response = new ResponseJson
	{
		Status = true,
		Message = "my message",
		LogId = "my log id",
		LogStatus = "my log status",
		FailureReason = "my failure reason"
	};

	var options = new JsonSerializerOptions
	{
		WriteIndented = true,
	};
	var json = JsonSerializer.Serialize(response, options);
	Console.WriteLine("Serialized {0}", response);
	Console.WriteLine(json);
}

{
  "Status": true,
  "Message": "my message",
  "LogId": "my log id",
  "LogStatus": "my log status",
  "FailureReason": "my failure reason"
}

Camel case for all JSON property names

By default, the JSON property names match the C# property names. If you want to convert them to camel case, you can use the JsonNamingPolicy.CamelCase option as shown below:

void Main()
{
	var response = new ResponseJson
	{
		Status = true,
		Message = "my message",
		LogId = "my log id",
		LogStatus = "my log status"
	};
	var serializeOptions = new JsonSerializerOptions
	{
		PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
		WriteIndented = true
	};
	var json = JsonSerializer.Serialize(response, serializeOptions);
	Console.WriteLine("Serialized {0}", response);
	Console.WriteLine(json);
}
Serialized ResponseJson
{
  "status": true,
  "message": "my message",
  "logId": "my log id",
  "logStatus": "my log status"
}

Use a custom JSON property naming policy

Assume you want to change the JSON property name before sending it to the server. You can easily do it using the Microsoft JSON library

Step 1: Create a custom class and implement the JsonNamingPolicy abstract class

public class SnakeNamePolicy : JsonNamingPolicy
{
	public override string ConvertName(string name)
	{
		return ToUnderscoreCase(name);
	}
	private string ToUnderscoreCase(string str)
	=> string.Concat((str ?? string.Empty).Select((x, i) => i > 0 && char.IsUpper(x) && !char.IsUpper(str[i - 1]) ? $"_{x}" : x.ToString())).ToLower();

}

In the ConvertName method, write the transformation logic. In this example, I’m converting the name to snake case.

Step 2: Pass the newly created policy to JsonSerializerOptions and use it in the Serialize method

void Main()
{
	var response = new ResponseJson
	{
		Status = true,
		Message = "my message",
		LogId = "my log id",
		LogStatus = "my log status"
	};
	var serializeOptions = new JsonSerializerOptions
	{
		PropertyNamingPolicy = new SnakeNamePolicy(),
		WriteIndented = true
	};
	var json = JsonSerializer.Serialize(response, serializeOptions);
	Console.WriteLine("Serialized {0}", response);
	Console.WriteLine(json);
}

By passing the SnakeNamePolicy instance to PropertyNamingPolicy in the JsonSerializerOptions, the property names will be transformed to snake case during serialization.

ouput

Serialized ResponseJson
{
  "status": true,
  "message": "my message",
  "log_id": "my log id",
  "log_status": "my log status"
}

Convert Enum to String

By default, enums are serialized as their underlying integer values. If you want to serialize enums as strings, you can use the JsonStringEnumConverter attribute. Here’s an example:

var serializeOptions = new JsonSerializerOptions
	{
		Converters =
			{
            	new JsonStringEnumConverter(JsonNamingPolicy.CamelCase)
			}
	};

public class ResponseJson
{
	public bool Status { get; set; }
	public string Message { get; set; }
	public string LogId { get; set; }
	public string LogStatus { get; set; }
	public Severity Severity { get; set; }

}
public enum Severity
{
	Low,
	High,
	Critical
}

void Main()
{

	var response = new ResponseJson
	{
		Status = true,
		Message = "my message",
		LogId = "my log id",
		LogStatus = "my log status",
		Severity = Severity.Critical
	};
	var serializeOptions = new JsonSerializerOptions
	{
		Converters =
			{
            	new JsonStringEnumConverter(JsonNamingPolicy.CamelCase)
			}
	};
	var json = JsonSerializer.Serialize(response, serializeOptions);
	Console.WriteLine("Serialized {0}", response);
	Console.WriteLine(json);
}

Output

Serialized ResponseJson
{"Status":true,"Message":"my message","LogId":"my log id","LogStatus":"my log status","Severity":"critical"}

Ignore Property

If you want to exclude a property from serialization and deserialization, you can use the JsonIgnore attribute. Here’s an example:

public class ResponseJson
{
    [JsonIgnore]
    public bool Status { get; set; }
    // ...
}

Ignore Read-Only Properties

By default, read-only properties are not serialized. If you want to include them in the serialization, you can use the IgnoreReadOnlyProperties attribute. Here’s an example:

var options = new JsonSerializerOptions
{
    IgnoreReadOnlyProperties = true,
    WriteIndented = true
};
jsonString = JsonSerializer.Serialize(weatherForecast, options);

Convert Property Value while Serializing

This is a compelling feature of the Microsoft Serializer library. Let’s suppose you want to serialize a property, but you want to do some preprocessing before that. In this example, I am converting the string to Base64.

void Main()
{

	var response = new ResponseJson
	{
		Status = true,
		Message = "my message",
		LogId = "my log id",
		LogStatus = "my log status",
		Severity = Severity.Critical
	};


	var json = JsonSerializer.Serialize(response);

	Console.WriteLine("Serialized {0}", response);
	Console.WriteLine(json);
}
public class StringToBase64JsonConvertor : JsonConverter<string>
{
	public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
	{
		return reader.GetString().ToLower();
	}

	public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options)
	{
		writer.WriteBase64StringValue(Encoding.UTF8.GetBytes(value));
	}
}
public class ResponseJson
{
	public bool Status { get; set; }
	public string Message { get; set; }
	public string LogId { get; set; }
	[JsonConverter(typeof(StringToBase64JsonConvertor))]
	public string LogStatus { get; set; }
	
	public Severity Severity { get; set; }

}
public enum Severity
{
	Low,
	High,
	Critical
}

Output

Serialized ResponseJson
{"Status":true,"Message":"my message","LogId":"my log id","LogStatus":"bXkgbG9nIHN0YXR1cw==","Severity":2}

Conclusion

Serialization and deserialization of JSON data in .NET provide a powerful and flexible way to work with JSON. You can control various aspects of the process, such as property naming, enum serialization, property exclusion, and custom conversion. These features allow you to fine-tune how your C# objects are represented in JSON, making it easier to work with JSON-based APIs and data interchange.

In this blog post, we explored some of the key concepts and techniques related to JSON serialization and deserialization in .NET. I hope this information helps you in your JSON handling tasks. Happy coding!

Next Post Previous Post
No Comment
Add Comment
comment url