If you recall when configuring the container via xml you can do a service override like so:
<configuration>
<components>
<component id="smtp.sender"
service="Namespace.IEmailSender, AssemblyName"
type="Namespace.SmtpMailSender, AssemblyName" />
<component id="sendmail.sender"
service="Namespace.IEmailSender, AssemblyName"
type="Namespace.SendMailEmailSender, AssemblyName" />
<component id="newsletter"
type="Namespace.NewsLetterSenderService, AssemblyName">
<parameters>
<sender>${smtp.sender}</sender>
</parameters>
</components>
</components>
</configuration>
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<IStaffRepository>().Named("repository.staff.a").ImplementedBy<StaffRepositoryA>().LifeStyle.Transient);
container.Register(Component.For<IStaffRepository>().Named("repository.staff.b").ImplementedBy<StaffRepositoryB>().LifeStyle.Transient);
}
[Fact]
public void ByDefaultStaffServiceWiredUpToFirstServiceRegistered()
{
container.Register(Component.For<IStaffService>().Named("service.staff").ImplementedBy<StaffService>().LifeStyle.Transient);
var staffService = (StaffService)container.Resolve<IStaffService>();
Assert.IsType<StaffRepositoryA>(staffService.Repository);
}
[Fact]
public void WithServiceOverrideCanPickImplmentationByKey()
{
container.Register(Component.For<IStaffService>().Named("service.staff").ImplementedBy<StaffService>()
.ServiceOverrides(ServiceOverride.ForKey("Repository").Eq("repository.staff.b")).LifeStyle.Transient);
var staffService = (StaffService)container.Resolve<IStaffService>();
Assert.IsType<StaffRepositoryB>(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 repository...
}
And the associated test - notice we just pass in a list of the service names...
[Fact]
public void WithServiceOverrideCanPickImplmentationByKey()
{
container.Register(Component.For<IStaffService>().Named("service.staff").ImplementedBy<StaffService>()
.ServiceOverrides(ServiceOverride.ForKey("Repositories").Eq("repository.staff.b", "repository.staff.a")).LifeStyle.Transient);
var staffService = (StaffService)container.Resolve<IStaffService>();
Assert.IsType<StaffRepositoryB>(staffService.Repositories[0]);
Assert.IsType<StaffRepositoryA>(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.