0

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:

  1. 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?
  2. Is the Text.Json the correct/best way to disable serialization on write?
  3. 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;
    }
}

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.