我最近将Autofac添加到一个大型的现有应用程序来管理DI.
在这个过程中,我用一个由容器管理的单个实例替换了单例,这个实例被注入到依赖的构造函数中.但是,在某些情况下,必须打破循环依赖关系.我发现这样做的最简单方法是利用OnActivated事件.我们打算修改这些类型以消除循环依赖关系,但现在更改它们的风险太大了.
对于循环依赖关系中涉及的类型,我添加了一个名为ResolveCircularDependencies的方法(这很明显,这个方法只是暂时使用,目的是解决这些循环).在OnActivated事件中调用此方法.
所以我的代码现在看起来像这样:
public class ServiceA
{
private ServiceB otherService;
public ServiceA()
{
...
}
public void ResolveCircularDependencies(ServiceB other)
{
this.otherService = other;
}
public void SomeMethod()
{
...
this.otherService.SomeMethod();
...
}
}
public class ServiceB
{
private ServiceA otherService;
public ServiceB()
{
...
}
public void ResolveCircularDependencies(ServiceA other)
{
this.otherService = other;
}
public void SomeMethod()
{
...
this.otherService.SomeMethod();
...
}
}
Run Code Online (Sandbox Code Playgroud)
这些类型在Autofac模块中注册,Load方法如下:
public override void Load(ContainerBuilder builder)
{
builder
.Register(ctx => new ServiceA())
.OnActivated(e => e.Instance.ResolveCircularDependences(e.Context.Resolve<ServiceB>()));
builder
.Register(ctx => new ServiceB())
.OnActivated(e => e.Instance.ResolveCircularDependences(e.Context.Resolve<ServiceA>()));
}
Run Code Online (Sandbox Code Playgroud)
在大多数情况下,这似乎可以正常工作.但是,我们随机看到Autofac认为它已找到循环依赖并返回以下堆栈跟踪,但有异常:
at Autofac.Core.Resolving.CircularDependencyDetector.CheckForCircularDependency(IComponentRegistration registration, Stack`1 activationStack, Int32 callDepth)
at Autofac.Core.Resolving.ResolveOperation.Resolve(ISharingLifetimeScope activationScope, IComponentRegistration registration, IEnumerable`1 parameters)
at Autofac.Core.Resolving.ComponentActivation.Resolve(IComponentRegistration registration, IEnumerable`1 parameters)
at Autofac.ResolutionExtensions.TryResolve(IComponentContext context, Service service, IEnumerable`1 parameters, Object& instance)
at Autofac.ResolutionExtensions.Resolve(IComponentContext context, Service service, IEnumerable`1 parameters)
at Autofac.ResolutionExtensions.Resolve[TService](IComponentContext context, IEnumerable`1 parameters)
at Autofac.ResolutionExtensions.Resolve[TService](IComponentContext context)
at DomainObjectFactory.Resolve[T]()
at DomainObjectFactory.BuildMyObject()
Run Code Online (Sandbox Code Playgroud)
我们还随机看到以下错误:
at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
at System.Collections.Generic.Stack`1.Enumerator.MoveNext()
at System.Linq.Enumerable.Count[TSource](IEnumerable`1 source, Func`2 predicate)
at Autofac.Core.Resolving.CircularDependencyDetector.IsCircularDependency(IComponentRegistration registration, Stack`1 activationStack)
at Autofac.Core.Resolving.CircularDependencyDetector.CheckForCircularDependency(IComponentRegistration registration, Stack`1 activationStack, Int32 callDepth)
at Autofac.Core.Resolving.ResolveOperation.Resolve(ISharingLifetimeScope activationScope, IComponentRegistration registration, IEnumerable`1 parameters)
at Autofac.Core.Resolving.ComponentActivation.Resolve(IComponentRegistration registration, IEnumerable`1 parameters)
at Autofac.ResolutionExtensions.TryResolve(IComponentContext context, Service service, IEnumerable`1 parameters, Object& instance)
at Autofac.ResolutionExtensions.Resolve(IComponentContext context, Service service, IEnumerable`1 parameters)
at Autofac.ResolutionExtensions.Resolve[TService](IComponentContext context, IEnumerable`1 parameters)
at Autofac.ResolutionExtensions.Resolve[TService](IComponentContext context)
at DomainObjectFactory.Resolve[T]()
at DomainObjectFactory.BuildMyObject()
Run Code Online (Sandbox Code Playgroud)
所有注册完成后都会发生这种情况(在应用程序启动时在单个线程上发生).可以在单独的线程上同时调用BuildMyObject方法.然而,根据Autofac维基,这似乎是可以接受的.
我已经回顾了ServiceA和ServiceB的完整依赖树,并且对象树中没有循环.
有没有人见过这种行为?分辨率是多少?
我们使用Autofac 2.3.2.632-NET35作为发布下载这里.
在IComponentContext您DomainObjectFactory被调用到似乎是暂时的,这是一个单一的解决操作过程中创建的,例如c在类似的参数:
builder.Register(c => new DomainObjectFactory(c))
Run Code Online (Sandbox Code Playgroud)
这些不是线程安全的; 正确的代码是:
builder.Register(c => new DomainObjectFactory(c.Resolve<IComponentContext>())
Run Code Online (Sandbox Code Playgroud)
这是一个令人讨厌的陷阱,偶尔出现,但通常是可以检测到的,因为一旦c被处理,Resolve()呼叫将抛出告密者ObjectDisposedException.我将在您链接到的并发页面上做一个注释.
| 归档时间: |
|
| 查看次数: |
1506 次 |
| 最近记录: |