I need to read older JSON with [Obsolete]
properties, but when writing JSON only the [Required]
properties should be written.
I still have a mix of older Newtonsoft.Json and newer Text.Json in .NET 8, and I'm looking for a solution in both.
I am using custom settings with a ContractResolver
in Newtonsoft.Json and a TypeInfoResolver
in Text.Json.
Questions:
- The Newtonsoft.Json logic does not read nor write the
[Obsolete]
attribute. Is there a mistake in the code, or do I need different settings for read and write? - Is the Text.Json the correct/best way to disable serialization on write?
- In both cases, can I detect if the serialization is to read or write and change behavior, or do I need different config for reading and for writing?
Example code:
// Text.Json settings
var jsonSerializerSettings = new JsonSerializerSettings()
{
Formatting = Formatting.Indented,
StringEscapeHandling = StringEscapeHandling.EscapeNonAscii,
NullValueHandling = NullValueHandling.Ignore,
ObjectCreationHandling = ObjectCreationHandling.Reuse,
ContractResolver = new ExcludeObsoletePropertiesResolver()
};
// Newtonsoft.Json options
var jsonSerializerOptions = new JsonSerializerOptions()
{
WriteIndented = true, // Formatting = Formatting.Indented,
Encoder = null, // StringEscapeHandling = StringEscapeHandling.EscapeNonAscii,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, // NullValueHandling = NullValueHandling.Ignore,
PreferredObjectCreationHandling = JsonObjectCreationHandling.Populate, // ObjectCreationHandling = ObjectCreationHandling.Reuse,
TypeInfoResolver = new DefaultJsonTypeInfoResolver()
.WithAddedModifier(JsonExtensions.ExcludeObsoleteProperties),
ReadCommentHandling = JsonCommentHandling.Skip,
AllowTrailingCommas = true
};
// JSON string
var jsonString = "{\"Required\":\"Required\",\"Obsolete\":\"Obsolete\"}";
// Newtonsoft
// Error, Obsolete is not read nor written
var schemaNewtonJson = Newtonsoft.Json.JsonConvert.DeserializeObject<Schema>(jsonString, jsonSerializerSettings);
var jsonNewtonJson = Newtonsoft.Json.JsonConvert.SerializeObject(schemaNewtonJson, jsonSerializerSettings);
// Text.Json
// Seems to work, Obsolete is read but not written
var schemaTextJson = System.Text.Json.JsonSerializer.Deserialize<Schema>(jsonString, jsonSerializerOptions);
var jsonTextJson = System.Text.Json.JsonSerializer.Serialize<Schema>(schemaTextJson, jsonSerializerOptions);
public record Schema
{
// Always read and write
[Required]
public string Required { get; set; } = "";
// Read but do not write
[Obsolete]
public string Obsolete { get; set; } = "";
}
public static class JsonExtensions
{
public static void ExcludeObsoleteProperties(JsonTypeInfo typeInfo)
{
if (typeInfo.Kind != JsonTypeInfoKind.Object)
return;
foreach (var property in typeInfo.Properties)
{
// Do not serialize Obsolete items
if (property.AttributeProvider?.IsDefined(typeof(ObsoleteAttribute), true) == true)
property.ShouldSerialize = (object _, object? _) => { return false; };
}
}
}
public class ExcludeObsoletePropertiesResolver : DefaultContractResolver
{
protected override List<MemberInfo> GetSerializableMembers(Type objectType)
{
var memberList = base.GetSerializableMembers(objectType);
// Remove all Obsolete items
memberList.RemoveAll(item => item.IsDefined(typeof(ObsoleteAttribute), true));
return memberList;
}
}