0

I'm trying to achieve the following dependency injection scenario using Autofac.

Suppose I have three classes, A, B and P. Class A holds a property of type P and also has a reference to B, which needs to be injected at runtime.

class A
{
    private B _b;

    public P Prop { get; set; }

    InitializeProp()
    { ... }
}

At the same time, class B depends on a instance of P:

class B
{
    private P _p;
}

Now, the most important detail: I need to somehow inject into B an instance of P. However, that instance must be Prop from class A, which is initialized only after InitializeProp() in A has been called. Assume InitializeProp() can be called later in the object's life time than the constructor of A.

Is this scenario achievable with Autofac?

I tried doing something like this but I get a circular reference exception, presumably when B is resolved further on:

containerBuilder.RegisterType<A>().SingleInstance();

containerBuilder.Register<Func<P>>(c =>
{
    var a = c.Resolve<A>();
    return () => a.Prop;
});
Gabriel S.
  • 1,347
  • 11
  • 31

2 Answers2

2

To be able to grasp a registrational problem, I often find it useful to construct the desired object graph by hand in code. Without the use of a DI container, this is what you wish to achieve:

var p = new P();
var a = new A(new B(p)) { P = p };

What you can see is that the instance of P is reused throughout the graph to achieve this. With this knowledge we can now determine what you need to do to achieve what you want.

So the solution is to configure Autofac to reuse the same instance of P. Since you regisered A as SingleInstance there is no other option than registering P as SingleInstance as well, otherwise you will be dealing with a Captive Dependency.

But if we take a step back, I see no reason for P being a property of A. As a matter of fact, there is hardly ever a good reason for using property injection.

You should always use constructor injection. So your classes should look as follows:

class A { public A(B b, P p) { } }
class B { public B(P p) { } }

This removes the configuration trouble completely, because you can simply do the following:

containerBuilder.RegisterType<A>().SingleInstance();
containerBuilder.RegisterType<B>().SingleInstance();
containerBuilder.RegisterType<P>().SingleInstance();
Steven
  • 166,672
  • 24
  • 332
  • 435
  • Ideally I'd design my classes as you suggest, P injected through constructor in A and B. However, my real scenario is constrained by other dependencies and, long story short, there's no way to circumvent having property P in class A, which is initialized at a certain point in A's lifetime. A implements an interface where property P is declared. – Gabriel S. Oct 14 '16 at 15:17
0

So eventually I figured it out, turns out Autofac is smarter than i thought.

It wasn't necessary to explicitly register a Func of P, but instead have this simplified registration:

builder.RegisterType<A>().SingleInstance();

builder.Register(c =>
{
  var a = c.Resolve<A>();
  return a.Property;
});

builder.RegisterType<B>();

Now in the main program i can do the following:

var a = container.Resolve<A>();
a.InitializeProperty();
a.Execute(); // calls B
Gabriel S.
  • 1,347
  • 11
  • 31