I have code similar to this:
class A: IA { ... }
class B: IB {
public B(IA a, ...) { ... }
...
}
class C1 {
public C1(IA a, IB b, ...) { ... }
}
class C2 {
public C2(IA a, IB b, ...) { ... }
}
What I want is only two instances of A -- one to go with C1 and one to go with C2. I want two instances of B. The instance of B passed to C1 should get the same instance of A created for C1. C2 and his parameters should have a different instance of A. How can I configure this scenario in Autofac? It looked like the Owned instance lifetime feature was supposed to handle this, but the posted example was only one layer deep, not two.
My real situation is much more complex. I have a dozen inheritors of IB and a half dozen C defs that take various combinations of the IB inheritors. I wanted to avoid using the named instances because that would bloat my bootstrapper significantly and make it difficult to maintain.
Secondary question: does DryIoc support this? I could be talked into switching.
You're looking for something called "instance per graph" lifetime scope. It is not supported natively by autofac. If you're not stuck with autofac you can use Castle Windsor as explained in this related/duplicate question.
If you're looking for a solution with autofac itself, you can implement it with InstancePerMatchingLifetimeScope
or InstancePerLifetimeScope
.
Here's how you configure your container
private IContainer Build()
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<A>().As<IA>().InstancePerMatchingLifetimeScope("SomeTag");
builder.RegisterType<B>().As<IB>().InstancePerMatchingLifetimeScope("SomeTag");
builder.RegisterType<C1>();
return builder.Build();
}
Here's how you use it
[Test]
public void PerGraphLifeStyle()
{
var container = Build();
C1 c1;
C1 c2;
using (var scope = container.BeginLifetimeScope("SomeTag"))
{
c1 = scope.Resolve<C1>();
Assert.AreSame(c1.A, c1.B.A);
}
using (var scope = container.BeginLifetimeScope("SomeTag"))
{
c2 = scope.Resolve<C1>();
Assert.AreSame(c1.A, c1.B.A);
}
Assert.AreNotSame(c1.A, c2.A);
}
Dummy classes I created for testing are below
internal interface IA
{
}
class A : IA
{
}
internal interface IB
{
IA A { get; set; }
}
class B : IB
{
public B(IA a)
{
A = a;
}
public IA A { get; set; }
}
class C1
{
public IA A { get; set; }
public IB B { get; set; }
public C1(IA a, IB b)
{
A = a;
B = b;
}
}