Isn't it annoying to have to register all your repository implementations by hand? When you get to a certain number of them, it becomes quite a task. If you want to register them for multiple interfaces, it gets even worse.
When using Windsor as your inversion of control container, separating your repository registrations into a facility is a good start. In general though, all our repositories follow a simple pattern and should be easily registerable automatically following an algorithm.
Domain driven design tells us that the repository interfaces are a part of the domain but the implementations are not. Therefore, we usually have two assemblies that are important.
This is a typical project layout:

Our facility needs to allow us to configure what assemblies it searches for types and the base type of the repository.
Specification
Here is a simple test describing the desired behavior:
[TestFixture]
public class RepositoryRegistrationFacilityTestFixture
{
[Test]
public void ShouldRegisterCustomerRepository()
{
var kernel = new Castle.MicroKernel.DefaultKernel();
var facility = new RepositoryRegistrationFacility(typeof (IRepository<>), typeof (Customer).Assembly);
facility.Init(kernel,
new Castle.Core.Configuration.MutableConfiguration("facility-config"));
kernel.Resolve<ICustomerRepository>().ShouldBeInstanceOfType(typeof (CustomerRepository));
kernel.Resolve<IRepository<Customer>>().ShouldBeInstanceOfType(typeof (CustomerRepository));
}
protected interface IRepository<T>
{
}
protected interface ICustomerRepository : IRepository<Customer>
{
}
protected class CustomerRepository : ICustomerRepository
{
}
protected class Customer
{
}
}
Implementation
public class RepositoryRegistrationFacility : AbstractFacility
{
private readonly Assembly[] assemblies;
private readonly Type genericRepositoryType;
public RepositoryRegistrationFacility(Type genericRepositoryType, params Assembly[] assemblies)
{
this.assemblies = assemblies;
this.genericRepositoryType = genericRepositoryType;
}
protected override void Init()
{
Predicate<Type> isGenericRepositoryInterface =
type =>
type.GetInterfaces().Contains(
x => x.IsGenericType && x.GetGenericTypeDefinition().IsAssignableFrom(genericRepositoryType));
IEnumerable<Type> types =
assemblies.Aggregate(Enumerable.Empty<Type>(), (accumulator, assembly) => accumulator.Concat(assembly.GetTypes()));
IEnumerable<Type> repositoryInterfaces = types.Where(
type => type.IsInterface && !type.IsGenericTypeDefinition && isGenericRepositoryInterface(type));
repositoryInterfaces
.ForEach(interfaceType =>
{
Type implementor =
types.FirstOrDefault(type => interfaceType.IsAssignableFrom(type) && !type.IsAbstract);
if (implementor == null) return;
IEnumerable<Type> genericRepositoryInterfaceTypes = implementor.GetInterfaces().Where(
x =>
x.IsGenericType &&
x.GetGenericTypeDefinition().IsAssignableFrom(genericRepositoryType));
Kernel.Register(
Component.For(interfaceType).ImplementedBy(implementor).Forward(
genericRepositoryInterfaceTypes));
});
}
}
Now in fluent configuration you can just do this:
container.AddFacility("persistent-repository-facility", new RepositoryRegistrationFacility(typeof(IRepository<>), typeof(IRepository<>).Assembly, typeof(SomethingRepository).Assembly));
I have not tested the binsor registration, but you should be able to do something like this to register it using binsor:
facility RepositoryRegistrationFacility:
genericRepositoryType: IRepository
assemblies: array(System.Reflection.Assembly, IRepository.Assembly, SomethingRepository.Assembly)
I hope this is useful.
