4

I am trying to register all classes that implement my IProcess<T1, T2> interface with Windsor. To accomplish this I have the following code in my installer:

        // Register all implemented process interfaces
        var procTypes = AppDomain.CurrentDomain
                                 .GetAssemblies()
                                 .SelectMany(x => x.GetTypes())
                                 .Where(x => x.IsDerivedFromOpenGenericType(typeof(IProcess<,>)))
                                 .ToList();

        foreach (var procType in procTypes)
            foreach (var procInterface in procType.GetInterfaces().Where(x => x.IsDerivedFromOpenGenericType(typeof(IProcess<,>))))
                container.Register(Component.For(procInterface).ImplementedBy(procType).LifeStyle.Transient);

One of the classes I a trying to register is the following:

public class PositionProcesses 
    : IProcess<CreatePositionParams, PositionDisplayViewModel>,
      IProcess<EditPositionParams, PositionDisplayViewModel>
{
}

The first interface gets registered correctly, but upon registering the second interface to be implemented by this class, I am getting the following error:

Test method MyJobLeads.Tests.Controllers.PositionControllerTests.Windsor_Can_Resolve_PositionController_Dependencies threw exception: 
Castle.MicroKernel.ComponentRegistrationException: There is a component already registered for the given key MyJobLeads.DomainModel.Processes.Positions.PositionProcesses

on the first loop iteration my variables are:

+       procInterface   {Name = "IProcess`2" FullName = "MyJobLeads.DomainModel.Data.IProcess`2[[MyJobLeads.DomainModel.ProcessParams.Positions.CreatePositionParams, MyJobLeads.DomainModel, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[MyJobLeads.DomainModel.ViewModels.Positions.PositionDisplayViewModel, MyJobLeads.DomainModel, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"}   System.Type {System.RuntimeType}
+       procType    {Name = "PositionProcesses" FullName = "MyJobLeads.DomainModel.Processes.Positions.PositionProcesses"}  System.Type {System.RuntimeType}

on the second:

+       procInterface   {Name = "IProcess`2" FullName = "MyJobLeads.DomainModel.Data.IProcess`2[[MyJobLeads.DomainModel.ProcessParams.Positions.EditPositionParams, MyJobLeads.DomainModel, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[MyJobLeads.DomainModel.ViewModels.Positions.PositionDisplayViewModel, MyJobLeads.DomainModel, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"} System.Type {System.RuntimeType}
+       procType    {Name = "PositionProcesses" FullName = "MyJobLeads.DomainModel.Processes.Positions.PositionProcesses"}  System.Type {System.RuntimeType}

(both of those are from the VS debugger.

Any ideas?

KallDrexx
  • 27,229
  • 33
  • 143
  • 254

2 Answers2

4

You should use convention based component registration

BasedOnDescriptor processes = AllTypes.FromAssembly(assemblyWithProcesses)
    .BasedOn(typeof (IProcess<,>))
    .WithService.AllInterfaces()
    .Configure(x => x.LifeStyle.Transient);

container.Register(processes)

EDIT removed first sample as mentioned by @Krzysztof-kozmic

hazzik
  • 13,019
  • 9
  • 47
  • 86
  • Ah I didn't notice that override. Worked like a charm, thanks :) – KallDrexx Aug 28 '11 at 04:26
  • I had to reread this a couple times to understand the difference from the OP's code. You're passing the interfaces array all at once to `For`, rather than one interface at a time. I will leave my answer, but I like this better because Windsor handles the naming for you :) – Merlyn Morgan-Graham Aug 28 '11 at 04:31
  • Added convention based registration example – hazzik Aug 28 '11 at 05:10
  • @KallDrexx: It is a little hazardous to trust that the assemblies you want are actually loaded. See http://stackoverflow.com/questions/3552223/. You can configure Windsor to find installers via your config file, so it probably wouldn't hurt to tighten up your type selection a bit (ala hazzik's convention based registration example) – Merlyn Morgan-Graham Aug 28 '11 at 05:23
  • 1
    I suggest removing the first code sample and stick just to the updated one. – Krzysztof Kozmic Aug 29 '11 at 06:40
2

If you have a single component registered for multiple services, I think you'll have to name each registration manually.

See: http://docs.castleproject.org/Windsor.Registering-components-by-conventions.ashx#Configuring_registration_13

container.Register(
    Component.For(procInterface)
             .ImplementedBy(procType)
             .LifeStyle.Transient
             .Named(component.Implementation.FullName
                 + "-"
                 + procInterface.Name)
    );

This should register each component by the type's full name plus the interface you're registering it for.

Merlyn Morgan-Graham
  • 58,163
  • 16
  • 128
  • 183
  • This option should work, but [I like hazzik's answer better](http://stackoverflow.com/questions/7218885/why-can-i-not-register-one-class-for-multiple-interfaces-in-windsor/7218994#7218994). – Merlyn Morgan-Graham Aug 28 '11 at 04:34