t3chb0t
t3chb0t

Reputation: 18675

Dependency injection with the new .net-core-3 json serializer

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.

Upvotes: 4

Views: 2883

Answers (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);

Upvotes: 1

Related Questions