0
votes

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, IEnumerable1 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(IEnumerable1 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, IEnumerable1 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(IEnumerable1 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, IEnumerable1 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(IEnumerable1 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, IEnumerable1 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, IEnumerable1 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

2
Can you post your stack trace on your circular reference exception.raterus
Changed the code to first register the Repository as a named service ("implementor"). This gives the stack trace added... Still a circular dependency. Dang!Cpt Slow
I've updated my answer with something to try, I think the problem is your newing up of Repository, rather than letting Autofac do it. If there is some good reason you need to do that, let me know whyraterus
I "newed it up" to be able to pass the resolved IEventStore, but you're probably right that this is not needed (the IEventStore should be resolved automatically). However, I tried your suggestion but I still get the same circular dependency, sadly.Cpt Slow

2 Answers

1
votes

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");
0
votes

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.