How to make AutoFac use same instance of nested de

2019-02-15 23:51发布

问题:

I am trying to set up my AutoFac registration in such a way that this test passes:

[Test]
public void Autofac_registration_test()
{
    // Given
    var builder = new ContainerBuilder();
    RegisterServices(builder);
    var container = builder.Build();

    // When
    var firstHub = container.Resolve<Hub>();
    var secondHub = container.Resolve<Hub>();

    // Then
    firstHub.Should().NotBe(secondHub);
    firstHub.FooRepo.Context.Should().Be(firstHub.BarRepo.Context);
    firstHub.FooRepo.Context.Should().NotBe(secondHub.FooRepo.Context);
}

i.e. I want to use the same Context object all the way down within a single Hub, but use a different one when a new Hub is created.

RegisterServices is currently just:

private void RegisterServices(ContainerBuilder builder)
{
    builder.RegisterType<MyHub>();
    builder.RegisterType<FooRepo>();
    builder.RegisterType<BarRepo>();
    builder.RegisterType<Context>(); // How should I scope this?
}

Which fails at firstHub.FooRepo.Context.Should().Be(firstHub.BarRepo.Context); because Context is transiently scoped.

But scoping context per lifetime also fails, this time at firstHub.FooRepo.Context.Should().NotBe(secondHub.FooRepo.Context);.

It feels like this is a reasonable thing to want to do, so am I missing anything obvious out-of-the-box here? Or will I have to do something manual to track Hub creation?

(For context, this is for a SignalR app. Hubs are created per SignalR request, so this was an attempt to match the unit-of-work lifetime of an HTTP request in normal webby situations).

回答1:

What @Steven said in his comment was correct, I needed a per-object-graph lifestyle.

Castle.Windsor supports this, so I swicthed to using that for my dependency injection instead of AutoFac. The registration now looks like:

container.Register(Component.For<Hub>().LifestyleTransient());
container.Register(Component.For<FooRepo>().LifestyleTransient());
container.Register(Component.For<BarRepo>().LifestyleTransient());
container.Register(Component.For<Context>().LifestyleBoundTo<Hub>()); // Important bit

For more information, see: http://docs.castleproject.org/Windsor.LifeStyles.ashx?HL=scope#Bound_8