Autofac根容器能否访问子作用域注册?单例依赖子服务如何跨作用域运行?
问题解答
1. childScope2中解析的Owner实例无法正常运行
你给出的代码运行到第二个using块时,Resolve<IOwner>本身不会抛出异常,但后续只要你调用Owner中用到IDog实例的逻辑,大概率会出现异常,根本无法正常运行,原因如下:
IOwner被注册为根容器的单例,全局只会被实例化一次:你第一次在childScope1中解析IOwner时,触发了Owner的构造函数,注入了childScope1中创建的Dog实例,这个Owner实例会一直存在于根容器的生命周期中,不会再重新创建。childScope1释放时,只会销毁当前作用域中创建的Dog实例,执行其Dispose方法,但不会清除Owner中对这个Dog实例的引用。此时Owner持有的是一个已经被释放的Dog对象,只要后续访问这个Dog的成员,就会触发ObjectDisposedException或者业务逻辑错误。- 你在
childScope2中解析IOwner时,Autofac直接返回已经创建好的单例Owner实例,不会重新走构造函数注入新的IDog,所以拿到的仍然是持有已释放Dog的旧实例,自然无法正常运行。
2. 根容器完全不能访问子作用域的注册项
你观察到的现象不代表根容器能访问子作用域的注册,这是Autofac的解析规则决定的:
Autofac触发解析时,所有依赖项的查找都是从发起Resolve调用的原始作用域开始,逐级向父作用域查找,而不是从服务注册的作用域开始查找。
你第一次能在childScope1中成功解析IOwner,是因为:
- 你从
childScope1发起Resolve<IOwner>调用,先向上查找到根容器的IOwner单例注册 - 构造
Owner需要IDog依赖,Autofac回到发起解析的原始作用域childScope1查找IDog,成功拿到注册完成注入
这个过程全程都是子作用域可以访问父作用域的注册,根容器自始至终都没有访问过childScope1的注册项。你可以尝试直接从根容器调用container.Resolve<IOwner>(),会直接抛出依赖缺失的异常,证明根容器看不到子作用域的任何注册。
额外提示
这是Autofac使用的常见坑:单例服务的生命周期和根容器绑定,远长于所有子作用域,所以不要让单例服务依赖仅在子作用域注册的服务,否则必然会出现依赖提前释放的问题。如果确实需要在单例中使用子作用域的服务,应该在调用逻辑中主动从当前上下文的作用域解析,而不是构造注入。
内容的提问来源于stack exchange,提问作者user16276760
相关产品推荐
相关产品推荐

