Microsoft has added high impact reliability, library extensibility, consistency, and performance-orientated features to improve the System.Text.Json library. Some of the improvements to the .NET library include:
- Contract customization
- Type hierarchies
- Required members
- JsonSerializerOptions.Default
System.Text.Json Updates
Let’s tackle each of the updates to System.Text.Json one-by-one.
Read: Best Online Courses to Learn C#
Contract Customization in .NET
Contract customization gives developers more control on type serialization and deserialization, user-defined type hierarchies, and support for required members. The System.Text.Json library figures out how a .NET type should be serialized and deserialized by establishing a JSON contract which is derived from the .NET type’s shape. This shape includes the properties and fields, the constructor, and checks the implementation of IEnumerable or IDictionary.
The metadata has always been JsonTypeInfo , but now, in .NET 7, all of its metadata has been exposed to be modifiable, thus allowing programmers to write their own resolution logic for the JSON contracts.
Here is a small code example showing how to define a custom contract resolver in .NET:
var JSONserOptions = new JsonSerializerOptions { TypeInfoResolver = new propertyContractResolver() }; JsonSerializer.Serialize(new { value = 44 }, JSONserOptions); public class propertyContractResolver : DefaultJsonTypeInfoResolver { public override JsonTypeInfo GetTypeInfo(Type t, JsonSerializerOptions o) { JsonTypeInfo type = base.GetTypeInfo(t, o); if (type.Kind == JsonTypeInfoKind.Object) { foreach (JsonPropertyInfo prop in type.Properties) { prop.Name = prop.Name.ToUpperInvariant(); } } return type; } }
Type Hierarchies in .NET
Polymorphic serialization and deserialization of user-defined type hierarchies is now supported by System.Text.Json. This can be done with the JsonDerivedTypeAttribute library. A code example follows demonstrating polymorphic serialization and deserialization in .NET:
[JsonDerivedType(typeof(DerivedClass))] public class Temp { public int i { get; set; } } public class DerivedClass : Temp { public int j { get; set; } }
The above code example enables polymorphic serialization for the Base class:
Base val = new DerivedClass(); JsonSerializer.Serialize(value);
The run-time type above is DerivedClass.
Required Members in .NET
With C# 11, support has been added for required members. This lets class authors specify properties and fields and the reflection serialization that must be populated when being instantiated. A quick C# code example follows:
using System.Text.Json; JsonSerializer.Deserialize("""{"StudentCourse": 7}"""); public class Student { public required string StudentName { get; set; } public int NumberOfSubjects { get; set; } }
With this, a JSON exception will be thrown because the required parameter (StudentName) was not supplied.
JsonSerializerOptions.Default
A read-only instance of JsonSerializerOptions can now be passed and accessed by developers through the use of the JsonSerializerOptions.Default static property. Here is some example code demonstrating this:
public class Convert : JsonConverter { private readonly static JsonConverter s_default = (JsonConverter)JsonSerializerOptions.Default.GetConverter(typeof(int)); public override void Write(Utf8JsonWriter w, int val, JsonSerializerOptions o) { return w.WriteStringValue(val.ToString()); } public override int Read(ref Utf8JsonReader r, Type type, JsonSerializerOptions o) { return s_default.Read(ref r, t, o); } }
Read more .NET programming tutorials and software development tips.