Skip to content

Instantly share code, notes, and snippets.

@tonysneed
Last active January 12, 2022 06:06
Show Gist options
  • Save tonysneed/5e7988516b081d454cde95b5d729e1af to your computer and use it in GitHub Desktop.
Save tonysneed/5e7988516b081d454cde95b5d729e1af to your computer and use it in GitHub Desktop.
Deserializing Interfaces with System.Text.Json

Demo: Deserialize Generic Interfaces with System.Text.Json

Demo of deserializing generic interfaces with System.Text.Json.

Problem

Deserializing to an interface will trigger an exception.

JsonSerializer.Deserialize<IMyInterface>(json);

Solution

  1. Create a JsonConverter for the interface.
public class InterfaceConverter<TImplementation, TInterface> : JsonConverter<TInterface>
    where TImplementation : class, TInterface
{
    public override TInterface? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        => JsonSerializer.Deserialize<TImplementation>(ref reader, options);

    public override void Write(Utf8JsonWriter writer, TInterface value, JsonSerializerOptions options)
    {
    }
}
  1. Create a generic JsonConverterFactory to create the interface converter.
public class InterfaceConverterFactory<TImplementation, TInterface> : JsonConverterFactory
{
    public Type ImplementationType { get; }
    public Type InterfaceType { get; }

    public InterfaceConverterFactory()
    {
        ImplementationType = typeof(TImplementation);
        InterfaceType = typeof(TInterface);
    }

    public override bool CanConvert(Type typeToConvert)
        => typeToConvert == InterfaceType;

    public override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions options)
    {
        var converterType = typeof(InterfaceConverter<,>).MakeGenericType(ImplementationType, InterfaceType);
        return Activator.CreateInstance(converterType) as JsonConverter;
    }
}
  1. Create JsonSerializationOptions with the converter factory and pass to JsonSerializer.Deserialize.
// Create deserializer options with interface converter factory.
var deserializerOptions = new JsonSerializerOptions
{
    Converters = { new InterfaceConverterFactory<MyClass, IMyInterface>() }
};

// Deserialize to the interface.
// This will trigger an exception without the options.
var myInterface = JsonSerializer.Deserialize<IMyInterface>(json, deserializerOptions);
if (myInterface is MyClass myClass2)
{
    // Use Implementation
}
public class InterfaceConverter<TImplementation, TInterface> : JsonConverter<TInterface>
where TImplementation : class, TInterface
{
public override TInterface? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
=> JsonSerializer.Deserialize<TImplementation>(ref reader, options);
public override void Write(Utf8JsonWriter writer, TInterface value, JsonSerializerOptions options)
{
}
}
public class InterfaceConverterFactory<TImplementation, TInterface> : JsonConverterFactory
{
public Type ImplementationType { get; }
public Type InterfaceType { get; }
public InterfaceConverterFactory()
{
ImplementationType = typeof(TImplementation);
InterfaceType = typeof(TInterface);
}
public override bool CanConvert(Type typeToConvert)
=> typeToConvert == InterfaceType;
public override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions options)
{
var converterType = typeof(InterfaceConverter<,>).MakeGenericType(ImplementationType, InterfaceType);
return Activator.CreateInstance(converterType) as JsonConverter;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment