Service overrides when using Windsor Fluent Component Registration

If you recall when configuring the container via xml you can do a
service override like so:




service="Namespace.IEmailSender, AssemblyName"
type="Namespace.SmtpMailSender, AssemblyName" />


service="Namespace.IEmailSender, AssemblyName"
type="Namespace.SendMailEmailSender, AssemblyName" />


type="Namespace.NewsLetterSenderService, AssemblyName">

${smtp.sender}


Check out the documentation on the
castle site
for some more details.

I recently got an email question around how to do this with the
fluent interface - unfortunately with the XML, Binsor and Fluent
interfaces all being used for registering and configuring the
MicroKernel/Windsor Container the documentation is a little patchy
across all three (with XML of course having the best coverage) - so
here's an example of service override for the fluent
interface.

First off the various services we'll be wiring up in this
example.

public interface IStaffService
{
}

public class StaffService : IStaffService
{
public IStaffRepository Repository { get; set; }
}

public interface IStaffRepository
{
}

public class StaffRepositoryA : IStaffRepository
{
}

public class StaffRepositoryB : IStaffRepository
{
}


And now the actual tests..
public class ServiceOverrideTests
{
private WindsorContainer container;

public ServiceOverrideTests()
{
container = new WindsorContainer();
container.Register(Component.For().Named("repository.staff.a").ImplementedBy().LifeStyle.Transient);
container.Register(Component.For().Named("repository.staff.b").ImplementedBy().LifeStyle.Transient);
}

[Fact]
public void ByDefaultStaffServiceWiredUpToFirstServiceRegistered()
{
container.Register(Component.For().Named("service.staff").ImplementedBy().LifeStyle.Transient);

var staffService = (StaffService)container.Resolve();

Assert.IsType(staffService.Repository);
}

[Fact]
public void WithServiceOverrideCanPickImplmentationByKey()
{
container.Register(Component.For().Named("service.staff").ImplementedBy()
.ServiceOverrides(ServiceOverride.ForKey("Repository").Eq("repository.staff.b")).LifeStyle.Transient);

var staffService = (StaffService)container.Resolve();

Assert.IsType(staffService.Repository);
}
}


With
.ServiceOverrides(ServiceOverride.ForKey("Repository").Eq("repository.staff.b"))
being the code we're interested in... obviously if it was a
constructor override we'd be using the name of the parameter in the
constructor.

The Eq method can also take of an array of strings... which,
you guessed it, means we can handle arrays of services as well ...
which can be quite handy if order is important to some kind of
service you're building where there are multiple contributors or
some form of pipeline, lets take a look at that:

public class StaffService : IStaffService
{
public IStaffRepository[] Repositories { get; set; } // <- is="" now="" an="" array="" of="" staff="">
}

And the associated test - notice we just pass in a list of the
service names...
[Fact]
public void WithServiceOverrideCanPickImplmentationByKey()
{
container.Register(Component.For().Named("service.staff").ImplementedBy()
.ServiceOverrides(ServiceOverride.ForKey("Repositories").Eq("repository.staff.b", "repository.staff.a")).LifeStyle.Transient);

var staffService = (StaffService)container.Resolve();

Assert.IsType(staffService.Repositories[0]);
Assert.IsType(staffService.Repositories[1]);
}


Hopefully this proves useful to Jason (who sent me the email) and
anyone else who's getting started with windsor and strugling a
little to setup their container.
Written on September 5, 2008