var self = justin();

Software Developer Teammate

A place to remind my future self of what I've learned and experienced. That means both my successes and failures.


Registering the same implementation twice

Ran into an issue today with Castle Windsor. For my current project, we use Castle Windsor to manage and inject our dependencies. It's a very powerful library that makes dependency injection a freaking breeze.

My problem was that I had a specific adapter I wanted to use during testing that was verbose in logging and also stubbed out a call to a third party web service. Now, by itself, that isn't a problem. The problem was that I had already registered an implementation for my ISomeServiceAdapter interface. So, when I tried to register my mock adapter, Castle Windsor threw an error:

 "Component Project.Library.Adapters.FakeService Adapter could not be registered. There is already a component with that name. Did you want to modify the existing component instead? If not, make sure you specify a unique name."

Uhh, what? I didn't register it! I had just written the class and was testing! Who the heck did?

Then I saw this in the assembly that I had created the mock adapter.

container.RegisterRemainingInterfaceImplementations();

Uhh, no idea what that is. Oh snap, this is from our code base!

public static IWindsorContainer RegisterRemainingInterfaceImplementations(this IWindsorContainer container)  
{
    Contract.Requires(container != null);
    container.RegisterRemainingInterfaceImplementations(LifestyleType.Singleton, Assembly.GetCallingAssembly());
    return container;
}
Drilling down again...
public static IWindsorContainer RegisterRemainingInterfaceImplementations(this IWindsorContainer container, LifestyleType lifestyle,Assembly assembly = null)  
{
    Contract.Requires(container != null);

    if (assembly == null)
    {
        assembly = Assembly.GetCallingAssembly();
    }

    container.Register(
        AllTypes.FromAssembly(assembly).Pick().Unless(t => t.GetInterfaces().Count() < 1)
        .Configure(comp => comp.LifeStyle.Is(lifestyle))
        .WithService.AllInterfaces().AllowMultipleMatches());

    return container;
}


Ok, well that's pretty slick. But it was also causing my problem. It was registering all of the implementations in the assembly if I hadn't already explicitly registered it. So to fix it, I needed to simply give a unique name to the registration in my testing assembly.

container.Register(Component.For<IService>().ImplementedBy<FaceService>().Named("OverridingFakeService").IsDefault());

The .Named("OverridingFakeService") is what fixes the issue. By default, Castle will assign a name to the implementation reference and that name is the full name of the implementation class. So when it tries to register the same implementation again, the name is no longer unique and then the error is thrown. So by specifying a different name, I can register the it again.

Done diddles! Ok, its not the perfect solution but it works.

On a side note, the extension method is from Tom Cabanski. Check out the rest of the code at the repo.

comments powered by Disqus