Reputation: 380
I get a circular dependency exception when trying to build the following with Autofac:
builder.RegisterType<Session>().As<ISession>();
builder.RegisterType<SFEventStore>().As<IEventStore>();
builder.RegisterType<MemoryCache>().As<ICache>();
builder.Register(c =>
{
return new CacheRepository(new Repository(c.Resolve<IEventStore>()), c.Resolve<IEventStore>(), c.Resolve<ICache>());
})
.As<IRepository>();
The problem is the IRepository, which resolves to a CacheRepository, while the CacheRepository depends on an IRepository:
public CacheRepository(IRepository repository, IEventStore eventStore, ICache cache);
The Repository takes an IEventStore in its constructor:
public class Repository : IRepository
{
private readonly IEventStore _eventStore;
public Repository(IEventStore eventStore)
{
_eventStore = eventStore ?? throw new ArgumentNullException(nameof(eventStore));
}
}
The CacheRepository follows the Decorator Pattern and adds functionality to the Repository:
public class CacheRepository : IRepository
{
private readonly IRepository _repository;
private readonly IEventStore _eventStore;
private readonly ICache _cache;
public CacheRepository(IRepository repository, IEventStore eventStore, ICache cache)
{
_repository = repository ?? throw new ArgumentNullException(nameof(repository));
_eventStore = eventStore ?? throw new ArgumentNullException(nameof(eventStore));
_cache = cache ?? throw new ArgumentNullException(nameof(cache));
}
So eventhough I new up a Repository in the Autofac builder method, Autofac still tries to resolve the IRepository in the CacheRepository constructor, which resolves to CacheRepository. Hence the circular dependency.
Tried to resolve this using an Autofac Decorator, like this:
builder.RegisterType<Session>().As<ISession>();
builder.RegisterType<SFEventStore>().As<IEventStore>();
builder.RegisterType<MemoryCache>().As<ICache>();
builder.Register(c =>
{
return new Repository(c.Resolve<IEventStore>());
})
.Named<IRepository>("implementor");
builder.RegisterDecorator<IRepository>(
(c, inner) => new CacheRepository(inner, c.Resolve<IEventStore>(), c.Resolve<ICache>()),
fromKey: "implementor");
But no luck. Still gives the circular dependency!
The chain starts with resolving a Session, which has the following ctor :
public Session(IRepository repository);
So I should get the following component dependency tree:
Session --> CacheRepository --> Repository --> SFEventStore
But instead it resolves to :
Session --> CacheRepository --> CacheRepository
This is the stack trace:
Autofac.Core.DependencyResolutionException: Circular component dependency detected: AnswersBC.Command.Handlers.AddAnswerCmdHandler -> CQRSlite.Domain.Session -> CQRSlite.Cache.CacheRepository -> CQRSlite.Cache.CacheRepository. at Autofac.Core.Resolving.CircularDependencyDetector.CheckForCircularDependency(IComponentRegistration registration, Stack1 activationStack, Int32 callDepth) in C:\BuildAgent\work\3206e2123f54fce4\src\NServiceBus.Core\Licensing\LogErrorOnInvalidLicenseBehavior.cs:line 0 at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable
1 parameters) in C:\BuildAgent\work\3206e2123f54fce4\src\NServiceBus.Core\Licensing\LogErrorOnInvalidLicenseBehavior.cs:line 0 at Autofac.Core.Activators.Reflection.ConstructorParameterBinding.Instantiate() in C:\BuildAgent\work\3206e2123f54fce4\src\NServiceBus.Core\Licensing\LogErrorOnInvalidLicenseBehavior.cs:line 0 at Autofac.Core.Activators.Reflection.ReflectionActivator.ActivateInstance(IComponentContext context, IEnumerable1 parameters) in C:\BuildAgent\work\3206e2123f54fce4\src\NServiceBus.Core\Licensing\LogErrorOnInvalidLicenseBehavior.cs:line 0 at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable
1 parameters) in C:\BuildAgent\work\3206e2123f54fce4\src\NServiceBus.Core\Licensing\LogErrorOnInvalidLicenseBehavior.cs:line 0 at Autofac.Core.Lifetime.LifetimeScope.GetOrCreateAndShare(Guid id, Func1 creator) in C:\BuildAgent\work\3206e2123f54fce4\src\NServiceBus.Core\Licensing\LogErrorOnInvalidLicenseBehavior.cs:line 0 at Autofac.Core.Resolving.InstanceLookup.Execute() in C:\BuildAgent\work\3206e2123f54fce4\src\NServiceBus.Core\Licensing\LogErrorOnInvalidLicenseBehavior.cs:line 0 at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable
1 parameters) in C:\BuildAgent\work\3206e2123f54fce4\src\NServiceBus.Core\Licensing\LogErrorOnInvalidLicenseBehavior.cs:line 0 at Autofac.Core.Activators.Reflection.ConstructorParameterBinding.Instantiate() in C:\BuildAgent\work\3206e2123f54fce4\src\NServiceBus.Core\Licensing\LogErrorOnInvalidLicenseBehavior.cs:line 0 at Autofac.Core.Activators.Reflection.ReflectionActivator.ActivateInstance(IComponentContext context, IEnumerable1 parameters) in C:\BuildAgent\work\3206e2123f54fce4\src\NServiceBus.Core\Licensing\LogErrorOnInvalidLicenseBehavior.cs:line 0 at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable
1 parameters) in C:\BuildAgent\work\3206e2123f54fce4\src\NServiceBus.Core\Licensing\LogErrorOnInvalidLicenseBehavior.cs:line 0 at Autofac.Core.Lifetime.LifetimeScope.GetOrCreateAndShare(Guid id, Func1 creator) in C:\BuildAgent\work\3206e2123f54fce4\src\NServiceBus.Core\Licensing\LogErrorOnInvalidLicenseBehavior.cs:line 0 at Autofac.Core.Resolving.InstanceLookup.Execute() in C:\BuildAgent\work\3206e2123f54fce4\src\NServiceBus.Core\Licensing\LogErrorOnInvalidLicenseBehavior.cs:line 0 at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable
1 parameters) in C:\BuildAgent\work\3206e2123f54fce4\src\NServiceBus.Core\Licensing\LogErrorOnInvalidLicenseBehavior.cs:line 0 at Autofac.Core.Activators.Reflection.ConstructorParameterBinding.Instantiate() in C:\BuildAgent\work\3206e2123f54fce4\src\NServiceBus.Core\Licensing\LogErrorOnInvalidLicenseBehavior.cs:line 0 at Autofac.Core.Activators.Reflection.ReflectionActivator.ActivateInstance(IComponentContext context, IEnumerable1 parameters) in C:\BuildAgent\work\3206e2123f54fce4\src\NServiceBus.Core\Licensing\LogErrorOnInvalidLicenseBehavior.cs:line 0 at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable
1 parameters) in C:\BuildAgent\work\3206e2123f54fce4\src\NServiceBus.Core\Licensing\LogErrorOnInvalidLicenseBehavior.cs:line 0 at Autofac.Core.Lifetime.LifetimeScope.GetOrCreateAndShare(Guid id, Func1 creator) in C:\BuildAgent\work\3206e2123f54fce4\src\NServiceBus.Core\Licensing\LogErrorOnInvalidLicenseBehavior.cs:line 0 at Autofac.Core.Resolving.InstanceLookup.Execute() in C:\BuildAgent\work\3206e2123f54fce4\src\NServiceBus.Core\Licensing\LogErrorOnInvalidLicenseBehavior.cs:line 0 at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable
1 parameters) in C:\BuildAgent\work\3206e2123f54fce4\src\NServiceBus.Core\Licensing\LogErrorOnInvalidLicenseBehavior.cs:line 0 at Autofac.Core.Resolving.ResolveOperation.Execute(IComponentRegistration registration, IEnumerable1 parameters) in C:\BuildAgent\work\3206e2123f54fce4\src\NServiceBus.Core\Licensing\LogErrorOnInvalidLicenseBehavior.cs:line 0 at Autofac.ResolutionExtensions.TryResolveService(IComponentContext context, Service service, IEnumerable
1 parameters, Object& instance) in C:\BuildAgent\work\3206e2123f54fce4\src\NServiceBus.Core\Licensing\LogErrorOnInvalidLicenseBehavior.cs:line 0 at Autofac.ResolutionExtensions.ResolveService(IComponentContext context, Service service, IEnumerable`1 parameters) in C:\BuildAgent\work\3206e2123f54fce4\src\NServiceBus.Core\Licensing\LogErrorOnInvalidLicenseBehavior.cs:line 0 at NServiceBus.AutofacObjectBuilder.Build(Type typeToBuild) in C:\BuildAgent\work\3206e2123f54fce4\src\NServiceBus.Core\ObjectBuilder\Autofac\AutofacObjectBuilder.cs:line 39 at NServiceBus.LoadHandlersConnector.d__1.MoveNext() in C:\BuildAgent\work\3206e2123f54fce4\src\NServiceBus.Core\Pipeline\Incoming\LoadHandlersConnector.cs:line 37
Upvotes: 0
Views: 1940
Reputation: 380
Seems to have to do something with the configuration of the components in NServiceBus :
nsbEndpointConfig.RegisterComponents(registration: configureComponents =>
{
configureComponents.ConfigureComponent<Session>(DependencyLifecycle.InstancePerUnitOfWork);
configureComponents.ConfigureComponent<SFEventStore>(DependencyLifecycle.InstancePerUnitOfWork);
configureComponents.ConfigureComponent<MemoryCache>(DependencyLifecycle.InstancePerUnitOfWork);
configureComponents.ConfigureComponent<Repository>(DependencyLifecycle.InstancePerUnitOfWork);
configureComponents.ConfigureComponent<CacheRepository>(DependencyLifecycle.InstancePerUnitOfWork);
});
When I omit this configuration, no circular dependency is detected. All I do here is setting the lifetimescopes however.
Upvotes: 0
Reputation: 2089
What you're describing sounds exactly like the Decorator pattern. You have two implementations of IRepository, and one wraps the other. Autofac supports this natively using .RegisterDecorator()
See the documentation here, http://docs.autofac.org/en/latest/advanced/adapters-decorators.html
I believe your "new"ing up of is the problem, see example below
Don't use this:
builder.Register(c =>
{
return new Repository(c.Resolve<IEventStore>());
})
.Named<IRepository>("implementor");
Instead use this:
builder.RegisterType<Repository>().Named<IRepository>("implementor");
builder.RegisterDecorator<IRepository>(
(c, inner) => new CacheRepository(inner, c.Resolve<IEventStore>(), c.Resolve<ICache>()),
fromKey: "implementor");
Upvotes: 1