Skip to content

RegisterDecorator corrupts resolution when a target registration has greater lifetime than per-dependency and IEnumerable<> is resolved #1113

@VonOgre

Description

@VonOgre

Reproduced in Autofac trunk DecoratorTests, but also noted in Autofac 5.1.2.

If one or more services (e.g. IService) are registered with a specific lifetime (InstancePerLifetimeScope, SingleInstance), resolving IEnumerable will return instances of all of the types as normal, but adding a decorator into the mix breaks the IEnumerable resolution, replacing all instances with the first "reusable" instance. Similarly, once IEnumerable is resolved, trying to resolve IService no longer returns the last registration, but instead also returns the "reusable" decorated instance noted in the IEnumerable case

[Fact]
        public void CanResolveMultipleDecoratedServicesSingleInstance()
        {
            var builder = new ContainerBuilder();
            builder.RegisterType<ImplementorA>().As<IDecoratedService>();
            builder.RegisterType<ImplementorB>().As<IDecoratedService>().SingleInstance();
            builder.RegisterDecorator<DecoratorA, IDecoratedService>();
            var container = builder.Build();

            var services = container.Resolve<IEnumerable<IDecoratedService>>();

            Assert.Collection(
                services,
                s =>
                {
                    Assert.IsType<DecoratorA>(s);
                    Assert.IsType<ImplementorA>(s.Decorated);
                },
                s =>
                {
                    Assert.IsType<DecoratorA>(s);
                    Assert.IsType<ImplementorB>(s.Decorated);
                });

            services = container.Resolve<IEnumerable<IDecoratedService>>();

            Assert.Collection(
                services,
                s =>
                {
                    Assert.IsType<DecoratorA>(s);
                    //Fails because s.Decorated is of type ImplementorB
                    Assert.IsType<ImplementorA>(s.Decorated);
                },
                s =>
                {
                    Assert.IsType<DecoratorA>(s);
                    Assert.IsType<ImplementorB>(s.Decorated);
                });
        }

[Fact]
        public void CanResolveSingleServiceAfterMultipleDecoratedServicesSingleInstance()
        {
            var builder = new ContainerBuilder();
            builder.RegisterType<ImplementorA>().As<IDecoratedService>().SingleInstance();
            builder.RegisterType<ImplementorB>().As<IDecoratedService>();
            builder.RegisterDecorator<DecoratorA, IDecoratedService>();
            var container = builder.Build();

            container.Resolve<IEnumerable<IDecoratedService>>();
            var service = container.Resolve<IDecoratedService>();

            Assert.IsType<DecoratorA>(service);
            //Fails because s.Decorated is of type ImplementorA
            Assert.IsType<ImplementorB>(service.Decorated);
        }

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions