System.Text.Json and Dynamically Parsing polymorphic objects

I ended up solving my issue in slightly the same way I had seen a previous article using a discriminator. Since I do not control the API feeds, I do not have a discriminator to drive off of, so I am relying on the properties of the Json object.

Need to create a Converter:

public class PolicyConfigurationSettingsConverter : JsonConverter<PolicyConfigurationSettings>
{
    public override PolicyConfigurationSettings Read( ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options )
    {
        JsonDocument doc;
        JsonDocument.TryParseValue( ref reader, out doc );

        if ( doc.RootElement.TryGetProperty( "minimumApproverCount", out _ ) )
            return JsonSerializer.Deserialize<MinimumNumberOfReviewers>( doc.RootElement.ToString(), options );
        if ( doc.RootElement.TryGetProperty( "useSquashMerge", out _ ) )
            return JsonSerializer.Deserialize<RequireAMergeStrategy>( doc.RootElement.ToString(), options );
        if ( doc.RootElement.TryGetProperty( "scope", out _ ) )
            return JsonSerializer.Deserialize<PolicyConfigurationSettingsScope>( doc.RootElement.ToString(), options );

        return null;
    }

    public override void Write( Utf8JsonWriter writer, [DisallowNull] PolicyConfigurationSettings value, JsonSerializerOptions options )
    {
        if ( value.GetType() == typeof( MinimumNumberOfReviewers ) )
            JsonSerializer.Serialize( writer, ( MinimumNumberOfReviewers )value, options );
        if ( value.GetType() == typeof( RequireAMergeStrategy ) )
            JsonSerializer.Serialize( writer, ( RequireAMergeStrategy )value, options );
        if ( value.GetType() == typeof( PolicyConfigurationSettingsScope ) )
            JsonSerializer.Serialize( writer, ( PolicyConfigurationSettingsScope )value, options );
    }
}

Then need to create a JsonSerializerOptions object to add the Converter

public static JsonSerializerOptions PolicyConfigurationSettingsSerializerOptions()
{
    var serializeOptions = new JsonSerializerOptions();
    serializeOptions.Converters.Add( new PolicyConfigurationSettingsConverter() );
    return serializeOptions;
}

Pass the options into your Serializer/Deserializer statement.

Below is the PolicyConfigurationSettings class

public abstract class PolicyConfigurationSettings
{
    [JsonPropertyName( "scope" )]
    public List<PolicyConfigurationScope> Scope { get; set; }
}

public class MinimumNumberOfReviewers : PolicyConfigurationSettings
{
    [JsonPropertyName( "minimumApproverCount" )]
    public int MinimumApproverCount { get; set; }
    [JsonPropertyName( "creatorVoteCounts" )]
    public bool CreatorVoteCounts { get; set; }
    [JsonPropertyName( "allowDownvotes" )]
    public bool AllowDownvotes { get; set; }
    [JsonPropertyName( "resetOnSourcePush" )]
    public bool ResetOnSourcePush { get; set; }
}

public class RequireAMergeStrategy : PolicyConfigurationSettings
{
    [JsonPropertyName( "useSquashMerge" )]
    public bool UseSquashMerge { get; set; }
}

public class PolicyConfigurationSettingsScope : PolicyConfigurationSettings { }

Leave a Comment