简体   繁体   中英

Nested registration with Autofac

Im trying to register a class as a specific interface and use explicit classes as paramerters to its constructor. The problem is they all implements the same interface which with my current registration ends up in a Autofac "Circular component dependency detected".

Here is what I got:

public interface IWorker
{
    void DoWork();
}
public class FirstLineWorker : IWorker
{
    public void DoWork()
    {
        //Do some work
    }
}
public class SecondLineWorker : IWorker
{
    public void DoWork()
    {
        //Do some morework
    }
}
public class SequentialWorker : IWorker
{
    private readonly IList<IWorker> _workers;

    public SequentialWorker(params IWorker[] workers)
    {
        _workers = workers;
    }

    public void DoWork()
    {
        foreach (var worker in _workers)
        {
            worker.DoWork();
        }
    }
}

How can I in Autofac programmatically register SequentialWorker as IWorker with explicit parameters FirstLineWorker and SecondLineWorker ?

First attempt which ended up in circular reigstration was:

var builder = new ContainerBuilder();
builder
    .RegisterType<FirstLineWorker>()
    .Named<IWorker>(typeof(FirstLineWorker).Name)
    .InstancePerDependency();
builder
    .RegisterType<SecondLineWorker>()
    .Named<IWorker>(typeof(SecondLineWorker).Name)
    .InstancePerDependency();
builder.RegisterType<SequentialWorker>()
    .As<IWorker>()
    .WithParameter(ResolvedParameter.ForNamed<IWorker>(typeof(FirstLineWorker).Name))
    .WithParameter(ResolvedParameter.ForNamed<IWorker>(typeof(SecondLineWorker).Name))
    .InstancePerDependency();

Any ideas?

There are at least 2 approaches available for you. First, create a new, empty interface, derived from IWorker , like

public interface IWorkExecutor : IWorker { }

Then, register "normal" workers as IWorker , and "executor" as IWorkExecutor

builder.RegisterType<Worker1>().As<IWorker>();
builder.RegisterType<Worker2>().As<IWorker>();
builder.RegisterType<SequentialWorker>().As<IWorkExecutor>();

Second approach would be quite similar to the code you already have:

containerBuilder.RegisterType<Worker1>().Named<IWorker>(nameof(Worker1));
containerBuilder.RegisterType<Worker2>().Named<IWorker>(nameof(Worker2));
containerBuilder.RegisterType<SequentialWorker>().As<IWorker>()
    .WithParameter(new ResolvedParameter(
        (pi, cc) => pi.Name == "workers",
        (pi, cc) => new [] { cc.ResolveNamed<IWorker>(nameof(Worker1)), cc.ResolveNamed<IWorker>(nameof(Worker2)) }));

You have to pass single array parameter for params IWorker[] workers in SequentialWorker .

BTW InstancePerDependency() is not actually needed, as this is the default lifetime scope when registering types.

This is answered in part by this question on the composite pattern (which is what you are implementing here).

The solution is to register all the services with a common name and resolve the named collection within the registration for the composite:

builder
    .RegisterType<FirstLineWorker>()
    .Named<IWorker>("worker")
    .InstancePerDependency();
builder
    .RegisterType<SecondLineWorker>()
    .Named<IWorker>("worker")
    .InstancePerDependency();

and either

builder
    .Register<IWorker>(c => new SequentialWorker(
            c.ResolveNamed<IEnumerable<IWorker>>("worker").ToArray()))
    .As<IWorker>()
    .InstancePerDependency();

or

builder.RegisterType<SequentialWorker>()
    .As<IWorker>()
    .WithParameter(new ResolvedParameter(
        (pi, cc) => pi.Name == "workers",
        (pi, cc) => cc.ResolveNamed<IEnumerable<IWorker>>("worker").ToArray()));

it's also worth mentioning that params is not really required, you can use IEnumerable as it avoids the need to execute ToArray() when resolving the "worker" 's

public SequentialWorker(IEnumerable<IWorker> workers)
{
    _workers = workers;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM