Skip to content

Instantly share code, notes, and snippets.

@flakey-bit
Created September 16, 2021 02:08
Show Gist options
  • Save flakey-bit/18a3d47973040fe3dd16916016c50dc8 to your computer and use it in GitHub Desktop.
Save flakey-bit/18a3d47973040fe3dd16916016c50dc8 to your computer and use it in GitHub Desktop.
System.Text.Json converter for Either<UnsupportedValue, T> - useful where T is an enum from a 3rd party API and you want to handle unknown values
internal class EitherValidOrUnsupportedValueConverterFactory : JsonConverterFactory
{
public override bool CanConvert(Type typeToConvert)
{
var canConvert = typeToConvert.IsGenericType && typeToConvert.GetGenericTypeDefinition() == typeof(Either<,>) && typeToConvert.GenericTypeArguments[0] == typeof(UnsupportedValue);
return canConvert;
}
public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
{
typeToConvert = typeToConvert.GenericTypeArguments[1];
return (JsonConverter)Activator.CreateInstance(typeof(EitherValidOrUnsupportedValueConverter<>).MakeGenericType(typeToConvert));
}
}
internal class EitherValidOrUnsupportedValueConverter<T> : JsonConverter<Either<UnsupportedValue, T>>
{
public override Either<UnsupportedValue, T> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
try
{
var deserialized = JsonSerializer.Deserialize<T>(ref reader, options);
return deserialized;
}
catch (JsonException ex)
{
return UnsupportedValue.Instance;
}
}
public override void Write(Utf8JsonWriter writer, Either<UnsupportedValue, T> value, JsonSerializerOptions options)
{
throw new NotImplementedException();
}
}
public record UnsupportedValue
{
public static readonly UnsupportedValue Instance = new UnsupportedValue();
private UnsupportedValue()
{
}
}
@flakey-bit
Copy link
Author

flakey-bit commented Sep 16, 2021

For anyone that uses System.Text.Json to consume a 3rd party API (esp where the API returns enum type values) you might find this converter handy.

Let's say nominally your DTO looks like this:

public class GoogleApiResponseDto
{
    public DayOfWeek Day { get; set; }

    public string SomeOtherField { get; set; }
}

But what if Google invents a new day like DeepFriday but doesn't tell you about it (or they tell you but you are too busy/forget)?
Well you can define your DTO like this instead for deserializing

public class GoogleApiResponseDto
{
    public Either<UnsupportedValue, DayOfWeek> Day { get; set; }

    public string SomeOtherField { get; set; }
}

You can still get the rest of the information from the DTO, and possibly gracefully handle the unsupported case somehow.
Note - this would mean modifying your code obviously (because now you need to handle both the cases where Day is a supported DayOfWeek value as well as cases where it's an UnsupportedValue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment