Saturday, September 06, 2008
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.
posted @ Friday, September 05, 2008 8:29:15 PM (New Zealand Standard Time, UTC+12:00)    Comments [4] | Trackback | Tracked by:
"Avoiding strings in your Windsor fluent config" (Bitter Coder) [Trackback]
Monday, September 08, 2008 8:15:50 AM (New Zealand Standard Time, UTC+12:00)
Is it possible to do the bulk of registrations via the fluent interface, and then allow for the possibility of XML overrides at runtime?
Peter Mounce
Monday, September 08, 2008 9:05:23 AM (New Zealand Standard Time, UTC+12:00)
You can certainly have both - one approach to use is to initialize the container with an xml/binsor configuration, and then to make all your fluent service registrations conditional on the service not having been registered already i.e. just use an extension method or an Unless predicate in your fluent registration i.e. say for controller registrations, you could using something along these lines:

Container.Register(AllTypes.Of<IController>().FromAssembly(currentAssembly).Unless(t=>Container.Kernel.HasComponent(t)));

For things like decorator chains however this is a little trickier... in my experience your better off creating a more explicit extensibility mechanism for anything that complex i.e. you'd create a specific decorator that would provide some kind of event or publish/subscribe mechanism, and provide a simple way for developers to register particpants, as opposed to using the container itself and relying on them understanding lifestyle etc.
Friday, October 03, 2008 10:10:37 AM (New Zealand Daylight Time, UTC+13:00)
I set up my dependencies by letting my different service types implement an interface. By doing that I don't have to change my registration every time I add a new service, repository, controller, etc.

Code is here:
http://blog.viabrains.com/2008/10/register-services-in-windsor.html
Friday, October 03, 2008 12:25:37 PM (New Zealand Daylight Time, UTC+13:00)
Hmmm...

I'm not a fan of that registration code myself for services, the first interface is very hit and miss and wouldn't be immediately obvious to someone refactoring the code that introducing an additional interface could disrupt just what service the component is mapped to (because order isn't guaranteed)... plus I can't help but feel that an IService marker interface is a code smell, better handled through the use of a class attribute.

That said if I was going to use a class attribute to mark services I'd probably just go the whole hog and use the CastleComponentAttribute, allowing me to specify a service type, key and lifestyle for each service- though at that point you're not really gaining anything.

Another approach might be to just use an attribute like [Component] to mark classes that need registering, and then decorating the service with an attribute like [Service] so your registration code could correctly pick the first "service" interface implemented by the component, rather then just the first service... this avoids some repetition (and obviously DRY == good).

All that said your approach is certainly concise, and the less component registration code you need to maintain the better! though for me I'm not sure how well it would work out i.e. I tend to make use of generic repositories and decorator chains quite often, and obviously order of registration etc. is important in these cases, so I generally need to be quite explicit about what I register.




Comments are closed.
Search
FeedCount

Tags...
Who am I?
Alex Henderson
Alex Henderson
Auckland, New Zealand
Managing Director at Dev|Defined Limited

"Self Confessed Coding Junky for 15 years"
View Alex Henderson's profile on LinkedIn
 
Mobile: +64-21-402-969
Email: bittercoder 'at' gmail 'dot' com
MSN: bittercoder_nz@hotmail
Skype: alex.devdefined
Navigation