2
votes

I have the following class/interface structure:

class ProviderSetting
{
    public delegate ProviderSetting Factory(string applicationClientId,
        string appKey);

    public ProviderSetting (string applicationClientId, string appKey)
    { ... }
}

and

class Provider : IProvider
{
    public Provider(ProviderSetting setting)
    { ... }
}

and

class Ingestor: IIngestor
{
    public Ingestor (IProvider provider)
    { ... }
}

I use autofac to perform dependency injection in the following manner:

var builder = new ContainerBuilder();
builder.RegisterType<ProviderSetting>().AsSelf();
builder.RegisterGeneratedFactory(typeof(ProviderSetting.Factory));
builder.RegisterType<Provider>().As<IProvider>();
builder.RegisterType<Ingestor>().As<IIngestor>();

and resolve as follows:

var settings = container.Resolve<ProviderSetting.Factory>().Invoke("<appId>", "<appKey>");
var provider = container.Resolve<IProvider>(new TypedParameter(typeof(ProviderSetting), settings));
var ingestor = container.Resolve<IIngestor>(new TypedParameter(typeof(Provider), provider));

But I get the exception that:

DependencyResolutionException: None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'ProviderSettings' can be invoked with the available services and parameters: Cannot resolve parameter 'System.String applicationClientId' of constructor 'Void .ctor(System.String, System.String)'.

What am I missing here?

1
It's trying to inject a ProviderSetting even though you're creating your own in the resolve stage. Have you tried adding a parameterless constructor to ProviderSetting, or resolving that separately? - Tim
I wanted to avoid adding parameterless constructor because the parameters are required by the ProviderSetting class and instantiating it without parameters would break the ingestor. - Dhruv Joshi

1 Answers

3
votes

The error occurs here:

var ingestor = container.Resolve<IIngestor>();

That's because autofac tries to resolve the Provider for Ingestor but for Provider it tries to resolve ParameterSettings which can't. The reason for this is that you haven't registered any parameters for ParameterSettings. The code:

var provider = container.Resolve<IProvider>(new NamedParameter("setting", new ProviderSetting ("<appId>", "<appKey>")));

Only resolves an instance of IProvider and does not register the above parameters.

To register those parameters you need to use WithParameters extension:

builder.RegisterType<ProviderSetting>()
    .AsSelf()
    .WithParameters(
    new[] 
    {
        new NamedParameter("applicationClientId", "someClientId"),
        new NamedParameter("appKey", "someAppKey")
    });

Then you can resolve services without explicitly providing those parameters:

var provider = container.Resolve<IProvider>();
var ingestor = container.Resolve<IIngestor>();

UPDATE: If you want to provide those arguments while resolving you could create factory delegate for this:

public delegate ProviderSetting ProviderSettingFactory(string applicationClientId, string appKey);

And register it:

containerBuilder.RegisterGeneratedFactory(typeof(ProviderSettingFactory));

Then you can resolve it like this:

var factory = container.Resolve<ProviderSettingFactory>();
ProviderSetting setting = factory("someClientId", "someAppKey");

In the end you can always do it like that:

var provider = container.Resolve<IProvider>(new NamedParameter("setting", new ProviderSetting ("<appId>", "<appKey>")));
var ingestor = container.Resolve<IIngestor>(new NamedParameter("provider", provider));