Search code examples
c#dependency-injectiondecoratorautofac

Autofac Open Generic Decorator with multiple interface causes circular dependency resolving


I have the following interfaces :

public interface ICommandHandler<T>
{
    void Handle(T command);
}

public class TransactionalCommandHandlerDecorator<T> : ICommandHandler<T>
{
    private readonly ICommandHandler<T> _handler;
    public TransactionalCommandHandlerDecorator(ICommandHandler<T> handler)
    {
        _handler = handler;
    }
    public void Handle(T command)
    {
    }
}

and I have a concrete class which implementing two command handlers :

public class Handler : ICommandHandler<CreateLocation>
                        ,ICommandHandler<ModifyLocation>
{
    public void Handle(CreateLocation command)
    {

    }

    public void Handle(ModifyLocation command)
    {
    }
}

and I have a registration as following :

 builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
            .AsClosedTypesOf(typeof(ICommandHandler<>))
            .InstancePerLifetimeScope();

    builder.RegisterGenericDecorator(typeof(TransactionalCommandHandlerDecorator<>), typeof(ICommandHandler<>));

Resolving 'Handler' class causes autofac to circularly resolving decorater and handler in an infinite loop which causes a StackOverflowException. if I a change 'Handler' to implement only one interface, then it will works without problem.

any idea on how to fix that?


Solution

  • This is a bug and will be addressed in a future release of Autofac. The fix looks like it will require a breaking change to another part of the API so will need to be released as part of v5.0.

    In the meantime, one way to work around the issue is creating separate registrations.

    var builder = new ContainerBuilder();
    builder.RegisterType<Handler>().As<ICommandHandler<CreateLocation>>();
    builder.RegisterType<Handler>().As<ICommandHandler<ModifyLocation>>();
    builder.RegisterGenericDecorator(typeof(TransactionalCommandHandlerDecorator<>), typeof(ICommandHandler<>));
    var container = builder.Build();
    
    var instance = container.Resolve<ICommandHandler<CreateLocation>>();