Search code examples
castle-windsorcastle-windsor-3

Castle Windsor: Register by convention, open generics


I have an interface like so:

public interface IGenericRepository<T>

I have a base class like so:

public abstract class GenericRepository<T> : IGenericRepository<T> where T : class

I have a class like so:

public class AGenericRepository<T> : GenericRepository<T> where T : class

Without convention, I successfully registered like so:

container.Register(
    Component.For(typeof(GenericRepository<>)).ImplementedBy(typeof(AGenericRepository<>))
);

I can successfully resolve an object like so:

var robot = container.Resolve<GenericRepository<Android>>();

However, when trying to register by convention like so:

container.Register(Classes.FromThisAssembly()
                            .BasedOn(typeof(GenericRepository<>))
                            .WithService.Base());

I cannot resolve as I did above. What gives?


Solution

  • Writing an answer since this may be too long (and codeful) for a comment.

    Given the following code:

    public interface IGenericRepository<T> {}
    public abstract class GenericRepository<T> : IGenericRepository<T> where T : class {}
    public class AGenericRepository<T> : GenericRepository<T> where T : class {}
    public class AInstance: AGenericRepository<string>{} 
    

    this registration works fine for me:

    var container = new WindsorContainer();
    container.Register(Classes.FromThisAssembly().BasedOn(typeof (GenericRepository<>)).WithServiceBase());
    var result = container.Resolve<GenericRepository<string>>();
    

    I have a feeling that we are lacking some information regarding what classes are registered.


    EDIT: in the proposed code apparently the abstract base class acts as a stop gap to determine what the base service is. If you use the following registration the resolution works:

    var container = new WindsorContainer();
    container.Register(Classes.FromThisAssembly().BasedOn(typeof (GenericRepository<>)).WithServiceAllInterfaces());
    var result = container.Resolve<IGenericRepository<string>>();
    

    However the resolution against the GenericRepository doesn't seem to work because it is not registered as a resolution component in castle. If you want to self register components you can describe it directly:

    var container = new WindsorContainer();
    container.Register(Classes.FromThisAssembly().BasedOn(typeof (GenericRepository<>)).WithServices(typeof(GenericRepository<>)));
    var result = container.Resolve<GenericRepository<string>>();
    // result is AGenericRepository<string>