4

I use this contract resolver for dependency-injection with Autofac and Json.NET:

public class AutofacContractResolver : DefaultContractResolver
{
    private readonly IComponentContext _container;

    public AutofacContractResolver(IComponentContext context)
    {
        _container = context ?? throw new ArgumentNullException(nameof(context));
    }

    protected override JsonObjectContract CreateObjectContract(Type objectType)
    {
        var contract = base.CreateObjectContract(objectType);

        // use Autofac to create types that have been registered with it
        if (_container.IsRegistered(objectType))
        {
            contract.DefaultCreator = () => _container.Resolve(objectType);
        }

        return contract;
    }
}

Then, I use it with DI to initialize the JsonSerializer:

var contractResolver = ctx.Resolve<IContractResolver>(); // ctx = Autofac's IComponentContext

var jsonSerializer = new JsonSerializer
{
    ContractResolver = contractResolver, // <-- AutofacContractResolver 
};


What would be the equivalent of this technique with the new System.Text.Json in net-core-3.0 - if there is any already? I wasn't able to figure this out and couldn't find any interfaces that would look similar to this ones.

Igal
  • 163
  • 1
  • 10
t3chb0t
  • 16,340
  • 13
  • 78
  • 118
  • 1
    This is interesting. I am not sure if something like this is built into it as yet. – Nkosi Nov 13 '19 at 12:36
  • @Nkosi I was afraid someone might say this. This would be a big show-stopper. I hope they'll implement something in the long run. – t3chb0t Nov 13 '19 at 12:39
  • 2
    The equivalent types in `System.Text.Json` -- [`JsonClassInfo`](https://github.com/dotnet/corefx/blob/master/src/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.cs) and [`JsonPropertyInfo`](https://github.com/dotnet/corefx/blob/master/src/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfo.cs) -- are **internal**. There is an open enhancement [Equivalent of DefaultContractResolver in System.Text.Json #42001](https://github.com/dotnet/corefx/issues/42001) asking for a public equivalent. – dbc Nov 26 '19 at 00:00
  • 2
    Related or duplicate: [System.Text.Json API is there something like IContractResolver](https://stackoverflow.com/q/58926112/3744182) which is also unanswered. – dbc Nov 26 '19 at 00:01

1 Answers1

1

Please try this library I wrote as an extension to System.Text.Json to offer missing features: https://github.com/dahomey-technologies/Dahomey.Json.

You will find support for programmatic object mapping.

Define your own implementation of IObjectMappingConvention:

public class AutofacObjectMappingConvention : IObjectMappingConvention
{
    private readonly IComponentContext _container;

    public AutofacObjectMappingConvention(IComponentContext context)
    {
        _container = context ?? throw new ArgumentNullException(nameof(context));
    }


    public void Apply<T>(JsonSerializerOptions options, ObjectMapping<T> objectMapping) where T : class
    {
        defaultObjectMappingConvention.Apply<T>(options, objectMapping);

        // use Autofac to create types that have been registered with it
        if (_container.IsRegistered(objectType))
        {
            objectMapping.MapCreator(o => _container.Resolve<T>());
        }
    }
}

Implement IObjectMappingConventionProvider to associate more than one type to the convention:

public class AutofacObjectMappingConventionProvider : IObjectMappingConventionProvider
{
    public IObjectMappingConvention GetConvention(Type type)
    {
        // here you could filter which type should be instantiated by autofac and return null for other types
        return new AutofacObjectMappingConvention();
    }
}

Setup json extensions by calling on JsonSerializerOptions the extension method SetupExtensions defined in the namespace Dahomey.Json:

JsonSerializerOptions options = new JsonSerializerOptions();
options.SetupExtensions();

Register the new object mapping convention for the class:

options.GetObjectMappingConventionRegistry().RegisterProvider(new AutofacObjectMappingConventionProvider());

Then serialize your class with the regular Sytem.Text.Json API:

string json = JsonSerializer.Serialize(myClass, options);