5

The autofac wiki page about Circular References says to use:

cb.Register<DependsByProp>().OnActivated(ActivatedHandler.InjectUnsetProperties);

But it looks like ActivatedHandler does not exist anymore in 2.4.5. Digging around in the source, I found the implementation of that class, and so I put in the method implementation in the OnActivated instead. Unfortunately, it this still doesn't work.

I've put together a minimal repro here that looks like what was on the Wiki page.

class M
{
    public VM VM { get; set; }

    public M()
    {
    }
}

class VM
{
    public VM(M m)
    {
    }
}

[Fact]
void CanResolveCircular()
{
    ContainerBuilder builder = new ContainerBuilder();

    builder.RegisterType<VM>();
    builder.RegisterType<M>().OnActivated(e => e.Context.InjectUnsetProperties(e.Instance));

    using (var container = builder.Build())
    {
        var m = container.Resolve<M>();
        Assert.NotNull(m);
    }
}

This code still throws a stack overflow exception as a Resolve is attempted. What am I missing? What is the correct way to get Autofac to handle circular dependencies?

Ants
  • 2,628
  • 22
  • 35
  • Yes. I thought that circular dependencies meant the same as instance cycles. Your answer below pointed out what I was missing about concepts of circular dependencies between classes and instances. – Ants May 31 '11 at 17:18

2 Answers2

7

The Autofac documentation for circular dependencies states:

Note, it doesn't make sense to set up this scenario if both classes are registered with Factory scope.

Both your M and VM registrations are InstancePerDependency (previously known as FactoryScope) so this statement applies to your scenario. As a result, you get in an endless loop of creating M and VM instances.

If you want the property injected VM to take the same instance of M that you resolve, you should change the lifetime of M to something other than InstancePerDependency (e.g. SingleInstance). This is shown below:

builder.RegisterType<M>().PropertiesAutowired(true).SingleInstance();

Note: I'm also using the more recent PropertiesAutowired(true) extension method. You can use this in place of the OnActivated code in your repro.

If you don't want a single instance of M per app, you could setup a LifetimeScope and use InstancePerLifetimeScope.

S. Baggy
  • 950
  • 10
  • 21
bentayloruk
  • 4,060
  • 29
  • 31
5

For anyone interested here is the new way of doing this:

class DependsByProp1
{
    public DependsByProp2 Dependency { get; set; }
}

class DependsByProp2
{
    public DependsByProp1 Dependency { get; set; }
}

// ...

var cb = new ContainerBuilder();
cb.RegisterType<DependsByProp1>()
      .InstancePerLifetimeScope()
      .PropertiesAutowired(PropertyWiringOptions.AllowCircularDependencies);
cb.RegisterType<DependsByProp2>()
      .InstancePerLifetimeScope()
      .PropertiesAutowired(PropertyWiringOptions.AllowCircularDependencies);

Property/Property Dependencies

StuartLC
  • 104,537
  • 17
  • 209
  • 285
MeTitus
  • 3,390
  • 2
  • 25
  • 49