Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Swapping Out Concrete Implementations of Interfaces with IoC/DI using Castle Windsor

0.00/5 (No votes)
15 Jan 2014 1  
How to swap out interface mappings in IoC/DI projects using Castle Windsor

IoC/DI Has Little Point If You Don't Swap your Maps

This tip is sort of an add-on to the article here

The whole point of Inversion of Control is so that you can pass different concrete implementations of an interface to a Controller that expects a class that implements a specific interface, but does not specify or even care what precise class it receives.

To specify which implementing class is used, you might write code such as this:

    public class RepositoriesInstaller : IWindsorInstaller
    {
        public void Install(IWindsorContainer container, IConfigurationStore store)
        {
            container.Register(
                Component.For<iduckbilledplatypusrepository>().ImplementedBy
                <duckbilledplatypusrepository>().LifestylePerWebRequest(),
                Component.For<isiberiantigerrepository>().ImplementedBy
                <siberiantigerrepository>().LifestylePerWebRequest(),
                Component.For<ibottlenoseddolphinrepository>().ImplementedBy
                <bottlenoseddolphinrepository>().LifestylePerWebRequest(),
                Component.For<ipterodactylrepository>().ImplementedBy
                <pterodactylrepository>().LifestylePerWebRequest(),
                Component.For<ibutterflyrepository>().ImplementedBy
                <butterflyrepository>().LifestylePerWebRequest());
        }
    }

But wait a minute -- "Whoa there, pard!" you might be saying. Isn't that a bit verbose? It's true there are other ways -- three, in fact - that you can map your interfaces (that is to say, the interfaces that are represented as argument types in your Controller's constructors): You can use XML files (which have the advantage of late binding), you can use auto-wiring or auto-registering, allowing the compiler to use reflection and register all interfaces you tell it to find, or you can do it in code, as shown above. The first way (XML) is largely considered passé today because of certain similarities with Peanut Brittle; the middle (auto-wiring) is definitely the hottest on the coolness scale (or the coolest on the...never mind); but I prefer the latter way, as shown above, for its easy readability. And, because it's easy to read, it's easy to maintain (if at times admittedly tedious) and to add grokkable logic to it.

As to the three ways of mapping your concrete classes to your interfaces, here is a (IMHO/YMMV) chart of their qualities/maladies:

Grokkability PIA Factor* FancyPantsiness
XML 10 8 2
Code 10 5 4
Auto-Wiring 2 2 10

*Note: PIA == "Pain In the Ankle"

Enough with the scientific charts, already!

So, let's get back down to business. As to using the "Code" method: For instance (no pun intended), if you want to swap out one set of implementers with another based on some condition, it is easy to add that sort of logic:

    const int HAPPINESS = 42;
    int Money;
    int Love;
    . . .
    public class RepositoriesInstaller : IWindsorInstaller
    {
        public void Install(IWindsorContainer container, IConfigurationStore store)
        {
	if (Love == HAPPINESS)
	{	
	            container.Register(
               		Component.For>imammalrepository>().ImplementedBy>
               		duckbilledplatypusrepository>().LifestylePerWebRequest(),
                		Component.For>ifishrepository>().ImplementedBy>
                		bottlenoseddolphinrepository>().LifestylePerWebRequest(),
                		Component.For>ibirdrepository>().ImplementedBy>
                		pterodactylrepository>().LifestylePerWebRequest(),
                		Component.For>ireptilerepository>().ImplementedBy>
                		hornedtoadrepository>().LifestylePerWebRequest());
                		Component.For>iinsectrepository>().ImplementedBy>
                		beetlerepository>().LifestylePerWebRequest());
	}
	else if (Money == HAPPINESS)
	{	
	            container.Register(
               		Component.For>imammalrepository>().ImplementedBy>
               		siberiantigerrepository>().LifestylePerWebRequest(),
                		Component.For>ifishrepository>().ImplementedBy>
                		catfishrepository>().LifestylePerWebRequest(),
                		Component.For>ibirdrepository>().ImplementedBy>
                		africangreyparrotrepository>().LifestylePerWebRequest(),
                		Component.For>ireptilerepository>().ImplementedBy>
                		bullfrogrepository>().LifestylePerWebRequest());
                		Component.For>iinsectrepository>().ImplementedBy>
                		prayingmantisrepository>().LifestylePerWebRequest());
	}
	else 
	{
		... // deal with it
	}
        }
    }

Of course, your conditional logic will differ (hopefully); and, for this to work, you will need to have created multiple (two, in this case) classes that implement each of the interfaces.

If different users should get different implementers, or if you want to use certain classes while debugging/testing and others for "production" code, this sort of scenario may come in handy for you.

That's all he wrote!

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here