Click here to Skip to main content
12,395,089 members (68,077 online)
Click here to Skip to main content
Add your own
alternative version

Stats

4.3K views
3 bookmarked
Posted

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

, 15 Jan 2014 CPOL
Rate this:
Please Sign up or sign in to vote.
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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

B. Clay Shannon
Founder "Across Time & Space"
United States United States
Ideaman and Coder at Across Time & Space, creator of "Mark Twain Central" at http://twaincentral.azurewebsites.net/

Peripatetic and picaresque, I have lived in eight states; specifically, besides my native California (where I was born and where I now again reside) in chronological order: New York, Montana, Alaska, Oklahoma, Wisconsin, Idaho, and Missouri.

I am also a writer of both fiction (for which I use a nom de plume, "Blackbird Crow Raven", as a nod to my Native American heritage - I am "½ Cowboy, ½ Indian") and nonfiction: http://www.lulu.com/spotlight/blackbirdcraven

You may also be interested in...

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.160721.1 | Last Updated 15 Jan 2014
Article Copyright 2014 by B. Clay Shannon
Everything else Copyright © CodeProject, 1999-2016
Layout: fixed | fluid