We know that Autofac has a concept of nested scopes and child scopes inherit registrations from parent scopes. Let's say we have the following code:
class Program
{
static void Main(string[] args) {
var builder = new ContainerBuilder();
builder.RegisterType<Owner>().As<IOwner>().SingleInstance();
IContainer container = builder.Build();
using (var childScope1 = container.BeginLifetimeScope(b => { b.RegisterType<Dog>().As<IDog>().InstancePerDependency(); })) {
IOwner owner= childScope1.Resolve<IOwner>();
}
// the injected Dog instance will be disposed when childScope1 is disposed
using (var childScope2 = container.BeginLifetimeScope()) {
IOwner owner = childScope2.Resolve<IOwner>();
}
}
}
// those interfaces, classes , inheritances are non meaningful, just for demo purpose
public interface IOwner: IDisposable { }
public interface IDog : IDisposable { }
public class Owner: IOwner{
IDog dog;
public Owner(IDog dog) {
this.dog = dog;
}
public void Dispose() { ...}
}
public class Dog: IDog {
public void Dispose() { ...}
}
You can see that I register Dog
as IDog
in childScope1 as transient, and Owner
depends on IDog
. So when I resolve IOwner
in childScope1, the singleton Owner
instance will be resolved from root container life scope but it's dependency Dog
is resolved in childScope1, because I registered Dog
in the child scope not in the root scope. So after the first using
statement, the transient Dog
instance is disposed (because the childScope1 is disposed).
So my question is, how can the singleton, shared instance owner
work properly in childScope2 when it's dependency Dog
has already been disposed? If it can work properly, does it mean that root container scope can access child scopes' registrations?
I'm not actually positive the code you provided will work. Did you try it, or is it hypothetical? Resolving the singleton will try to resolve all dependencies from the root lifetime scope (the container) and since the dependency registration doesn't exist in the root, resolution will fail.
The answers to the larger question of how this works is covered pretty well in the documentation including helpful diagrams. Here's a relevant snippet:
What affects this mechanism is the “lifetime” aspect of “lifetime scope.” Some components, like singletons need to be shared across multiple scopes. This affects how dependencies get located. The “basic rules” are:
- A child lifetime scope can get dependencies from parent scopes, but a parent scope may not reach down into a child scope. (You can locate things by moving “up the tree” but you can’t move “down the tree.”)
- A component will get its dependencies from the scope that owns the component even if the component is resolved by a scope further down the tree.
A lot of questions can be answered in a more practical fashion by writing a few small unit tests and getting hands-on experience with it. You can also browse through the existing Autofac unit tests and examples to see real code in action.