Case sensitivity in JSON deserialization
By FoxLearn 3/21/2025 2:24:24 AM 51
When deserializing JSON strings into objects, case sensitivity can cause issues. Specifically, if you're using case-sensitive deserialization, the property names in your JSON string must match the exact casing of the class properties. If there's a mismatch, the deserialization will fail, and properties with mismatched casing will be left null
.
This can be particularly tricky when switching between Newtonsoft.Json
and System.Text.Json
, as the deserialization behavior differs in terms of case sensitivity.
Here's a table showing the comparison of case sensitivity handling in Newtonsoft.Json
and System.Text.Json
:
Case Sensitivity | Newtonsoft.Json | System.Text.Json |
---|---|---|
Case insensitive deserialization | Default behavior | Pass in an option to make it case insensitive |
Case sensitive deserialization | Write a custom converter | Default behavior |
In this article, I'll walk through how to implement both case-sensitive and case-insensitive deserialization with Newtonsoft.Json
and System.Text.Json
.
Consider this example JSON, where the keys do not match the property names in the Person
class:
{ "firstName": "John", "lastName": "Doe", "age": 30 }
I want to deserialize this JSON into a Person
object, where the property names are FirstName
, LastName
, and Age
:
var person = new Person() { FirstName = "John", LastName = "Doe", Age = 30 };
Notice that the firstName
key in the JSON does not match the casing of the FirstName
property in the Person
class.
Case Insensitive Deserialization - Using System.Text.Json
System.Text.Json supports case-insensitive deserialization using the PropertyNameCaseInsensitive
setting:
using System.Text.Json; var json = "{\"firstName\": \"John\", \"lastName\": \"Doe\", \"age\": 30}"; var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; var person = JsonSerializer.Deserialize<Person>(json, options); Console.WriteLine($"Person.FirstName={person.FirstName}");
Output:
Person.FirstName=John
Case Insensitive Deserialization – Using Newtonsoft.Json
Newtonsoft.Json
performs case-insensitive deserialization by default, so this is straightforward:
using Newtonsoft.Json; var json = "{\"firstName\": \"John\", \"lastName\": \"Doe\", \"age\": 30}"; var person = JsonConvert.DeserializeObject<Person>(json); Console.WriteLine($"Person.FirstName={person.FirstName}");
Output:
Person.FirstName=John
Case Sensitive Deserialization – Using System.Text.Json
System.Text.Json
performs case-sensitive deserialization by default:
using System.Text.Json; var json = "{\"firstName\": \"John\", \"lastName\": \"Doe\", \"age\": 30}"; var options = new JsonSerializerOptions(); var person = JsonSerializer.Deserialize<Person>(json, options); Console.WriteLine($"Person.FirstName={person.FirstName}");
Output:
Person.FirstName=
In this case, FirstName
remains null
because the JSON key firstName
does not match the casing of the FirstName
property in the Person
class.
Case Sensitive Deserialization - Using Newtonsoft.Json
Unlike System.Text.Json
, case-insensitive deserialization is hardcoded in Newtonsoft.Json
, and making it configurable has been a feature request for years.
Option 1: Write a Custom Converter that Ignores Properties with Mismatched Casing
To achieve case-sensitive deserialization, you can write a custom converter.
Here's an example that filters out properties with mismatched casing:
using Newtonsoft.Json; using Newtonsoft.Json.Linq; public class CaseSensitivePersonDeserializer : JsonConverter { public override bool CanConvert(Type objectType) { return true; } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) return null; JObject target = new JObject(); foreach(JProperty property in JToken.Load(reader).Children()) { if(objectType.GetProperty(property.Name) != null) { target.Add(property); } } return target.ToObject(objectType); } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { JObject o = (JObject)JToken.FromObject(value); o.WriteTo(writer); } }
Now, use the custom converter during deserialization:
using Newtonsoft.Json; var json = "{\"firstName\": \"John\", \"lastName\": \"Doe\", \"age\": 30}"; var person = JsonConvert.DeserializeObject<Person>(json, new CaseSensitivePersonDeserializer()); Console.WriteLine($"Person.FirstName={person.FirstName}");
Output:
Person.FirstName=
Since there's no exact match for the FirstName
property, it's left null
.
Option 2: Modify the Newtonsoft.Json Repository for Case-Sensitive Matching
Newtonsoft.Json
is open-source, so you can modify the repository to make it case-sensitive by default. The method you need to alter is JsonPropertyCollection.GetClosestMatchProperty()
.
public JsonProperty? GetClosestMatchProperty(string propertyName) { JsonProperty? property = GetProperty(propertyName, StringComparison.Ordinal); if (property == null) { property = GetProperty(propertyName, StringComparison.OrdinalIgnoreCase); } return property; }
You would need to fork the repository, implement this change, and then generate a custom NuGet package for your project.
- Primitive types in C#
- How to set permissions for a directory in C#
- How to Convert Int to Byte Array in C#
- How to Convert string list to int list in C#
- How to convert timestamp to date in C#
- How to Get all files in a folder in C#
- How to use Channel as an async queue in C#
- The JSON value could not be converted to Enum