Skip to content

Duplicate named registrations fails silently when using BasedOnDescriptor.Configure #650

@ghost

Description

In my application, I'm using a custom attribute to provide info to Windsor that it can use to generate named registrations for different implementations of the same underlying service type.

The issue is that if a scenario is encountered where the same name would be used to register multiple components, then it creates a race condition, where the first type that Windsor discovers and registers will get added to the container, while the other types that try to register with the same name, simply do not get added to the container. No exception is triggered, which is the behavior I expected.

Unfortunately, I can't share the exact code, but here is some similar code that should reproduce the same issue. Whichever type is discovered by Windsor first , either ServiceImplementation1 or ServiceImplementation2, will get registered, while the attempt to register the 2nd component with the same name will fail silently.

namespace MyApp
{
    [AttributeUsage(AttributeTargets.Class)]
    public class CustomAttribute : Attribute
    {
        public string Key { get; }

        public CustomAttribute(string key)
        {
            Key = key;
        }
    }

    // the service type registered with the container
    public interface IServiceInterface { }

    // implementation #1
    [Custom("implementation1")]
    public class ServiceImplementation1 : IServiceInterface { }

    // implementation #2: this uses the same key as #1, to trigger a registration failure
    [Custom("implementation1")]
    public class ServiceImplementation2 : IServiceInterface { }

    public class WindsorInstaller : IWindsorInstaller
    {
        public void Install(IWindsorContainer container, IConfigurationStore store)
        {
            container.Register(
                Classes.FromAssemblyContaining<WindsorInstaller>()
                    .Where(t => typeof(IServiceInterface).IsAssignableFrom(t) &&
                                Component.HasAttribute<CustomAttribute>(t))
                    .Configure(reg =>
                    {
                        var attribute =
                            (CustomAttribute)Attribute.GetCustomAttribute(c.Implementation, typeof(CustomAttribute));
                        reg.Named($"{typeof(IServiceInterface).FullName}_{attribute.Key}");
                    })
            );


        }
    }
    
    public class Program
    {
        public static int Main(string[] args)
        {
            var container = new WindsorContainer().Install(FromAssembly.Containing<Program>());

            // resolves to whichever component happened to be discovered first
            var service = container.Resolve<IServiceInterface>($"{typeof(IServiceInterface).FullName}_implementation1");
            Console.WriteLine($"Resolved {service.GetType().Name}");

            // returns a single component (whichever one was successfully registered)
            var allServices = container.ResolveAll<IServiceInterface>();
            Console.WriteLine($"Discovered {allServices.Length} services that implement IServiceInterface");

            return 0;
        }
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions