0

I have an application that uses two different modules (implemented as Autofac.Module) that register the services they provide. Each simply has an adapter for hardware devices that produce the same data via different methods.

public class AdapterA : IDataProducer {
    public AdapterA(IConfigSource conf){
        // do something with conf, like setting an IP address, port etc.
    }
}

public ModuleA : Module{
    protected override void Load(ContainerBuilder builder)
     {
         builder.RegisterType<AdapterA>().As<IDataProducer>();
         // the config source is specific to Module A, as it contains details about the hardware
         builder.Register(c => new IniConfigSource("moduleA.ini")).As<IConfigSource>();
     }
}

Now when I register that module in my main application, it works fine and the dependencies are resolved correctly.

builder.RegisterModule<ModuleA>();

In my main application, I also make use of an IConfigSource, to read/write application specific settings. The problem becomes obvious when I register another IConfigSource there, with a different settings file.

protected override void ConfigureContainer(ContainerBuilder builder)
    {
        builder.RegisterModule<ModuleA>();
        builder.Register(c => new IniConfigSource("mainprogram.ini")).As<IConfigSource>();
    }

At Resolution time, the second registration takes effect and my ModuleA receives the wrong configuration file reader.

Looking around for a solution, I tried to work around this by changing the registration type, like so:

public interface IModuleAConfigSource : IConfigSource {}

and

builder.Register(c => new IniConfigSource("moduleA.ini")).As<IModuleAConfigSource>();

but that does not work. Autofac complains at resolution time that the type IniconfigSource is not assignable to the interface IModuleAConfigSource. I use constructor injection with registration in a single function at application startup.

What would be a good strategy here? I know I can use concrete types to solve this, but is there a way to keep a registration module-local, i.e. when resolving a type to use the registration from that module?

Progman
  • 16,827
  • 6
  • 33
  • 48
Krazykraut
  • 11
  • 2

1 Answers1

0

After more reading, I think keyed service registration will work for me. I register my IConfigSource with a module specific key, like so:

builder.Register(c => new IniConfigSource("moduleA.ini")).Keyed<IConfigSource>("moduleA");

and the type depending on the service as:

builder.RegisterType<ConcreteModuleAType>().AsSelf().WithAttributeFiltering();

The constructor of ConcreteModuleAType then has the attribute

  public ConcreteModuleAType([KeyFilter("moduleA")] IConfigSource configSource)    {
        this.configSource = configSource;
    }

This is a good solution for me. Only issue is that the order of module registration matters. The module has to be registered last as apparently a non-keyed registration overwrites a keyed one.

Krazykraut
  • 11
  • 2