Autocomplete circular dependency reports that do not exist

I recently added Autofac to a large existing DI management application.

In this process, I replaced the singleton with a single instance controlled by a container, which is injected into the dependent constructor. However, in some cases, circular dependencies had to be broken. The easiest way I've found for this is to use the OnActivated event. We intend to modify these types to eliminate circular dependencies, but the risk of changing them is now too great.

For types related to circular dependencies, I added a method called ResolveCircularDependencies (this makes it obvious that this method should only be used temporarily and in order to resolve these loops). This method is called in the OnActivated event.

So now my code looks like this:

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(); ... } } 

These types are registered in the Autofac module using the Download method as follows:

 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>())); } 

In most cases, this works correctly. However, we accidentally see that Autofac believes that it found a circular dependency and returns the following stack trace with an exception:

 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() 

We also randomly see the following error:

 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() 

This happens well after all registrations are completed (what happens in one thread when the application starts). Calls to the BuildMyObject method can be executed simultaneously in separate threads. This, however, seems to be acceptable according to the Autofac wiki .

I looked through all the ServiceA and ServiceB dependency trees, and there are no loops in the object trees.

Has anyone seen this behavior? What is permission?

We are using Autofac 2.3.2.632-NET35, released for download here .

+4
source share
1 answer

IComponentContext that your DomainObjectFactory is temporary, which was created during one resolution operation, for example. c parameter in something like:

 builder.Register(c => new DomainObjectFactory(c)) 

They are not thread safe; correct code:

 builder.Register(c => new DomainObjectFactory(c.Resolve<IComponentContext>()) 

This is an unpleasant gotcha that appears from time to time, but is usually detected, because after c is located, calling Resolve() will raise the ObjectDisposedException control string. I will make a note on the concurrency page that you linked to.

+6
source

All Articles