flow.
"Flow is a condition of deep, nearly meditative involvement." - Tom DeMarco

Windsor IoC Container in a Lunch Break

Thursday, July 12, 2007 1:30 PM
This is the first post in what will (hopefully) be an occasional series on great tools that are found in many agile developers' toolbox.  The goal of this series is to provide a light introduction to a given technology all the way from the ground up to being able to use the tool in some limited fashion...all in the period of about an hour.  That said, this means that we'll likely be light on theory and edge cases of the tool allowing us to focus only on what we need to start using the tool and then showing you where to look when you need deeper answers.

Windsor is the Inversion of Control (IoC) container piece of the Castle Project, the same guys that bring you MonoRail.  In the short, IoC containers act as a holding structure for the components of your application allowing you to easily decouple them from one another.  This gives you the flexibility to refactor as necessary, replace live implementations of objects with mocked ones, and basically do whatever is necessary to get your system running well in the shortest amount of time.  Although we'll be talking about Windsor exclusively, you may want to check out other .Net IoC containers such as Spring.NET or Jeremy Miller's StructureMap.

Now that I know what it is, where do I get it?  Head on over to the Castle Project's website and download the installer.  There's only one installer and it contains every Castle component available including Windsor, ActiveRecord, and MonoRail.   Once you have the framework installed, the necessary components will be added to your GAC and will even show up in the "Add References..." dialog of Visual Studio.

The only references that will be necessary to use the WindsorContainer are the Castle.Windsor and Castle.MicroKernel assemblies. 

Briefly, let's talk about the example that we'll be using.  Our example consumes a commerce web service, for the sake of our example, we'll assume its the Amazon E-Commerce Service.  This service is abstracted behind an ICommerceService interface which is implemented by a MockCommerceService, for testing, and an AmazonCommerceService for production.  Although this implementation of the AmazonCommerceService does not actually communicate with Amazon.com we'll pretend for the sake of the example that it does.

Here's the interface as well as the two separate implementations of it...

 

    /// <summary>

    /// Provides a true implementation of the commerce service.

    /// </summary>

    public class CommerceService : ICommerceService

    {

        #region ICommerceService Members

 

        /// <summary>

        /// Gets the price of the given item.

        /// </summary>

        /// <param name="item">The item for which to retrieve the price.</param>

        /// <returns>The price of the given item.</returns>

        public string GetPrice(string item)

        {

            return "99.99";

        }

 

        #endregion

    }


    /// <summary>

    /// Provides a mock implementation of the commerce service.

    /// </summary>

    public class MockCommerceService : ICommerceService

    {

        #region ICommerceService Members

 

        /// <summary>

        /// Gets the price of the given item.

        /// </summary>

        /// <param name="item">The item for which to retrieve the price.</param>

        /// <returns>The price of the given item.</returns>

        public string GetPrice(string item)

        {

            return "9.99";

        }

 

        #endregion

    }



We've included two tests for this service, one categorized as "Live" and another categorized as "Mocked".  We are able to simply switch between the two using the Windsor Container...

    /// <summary>

    ///Fully exercises the <see cref="CommerceService"/> object.

    /// </summary>

    [TestFixture]

    public class CommerceServiceTest

    {

        /// <summary>

        /// Determines whether this instance can successfully interact with a mocked commerce service.

        /// </summary>

        [Test]

        public void CanQueryCommerceService_Mocked()

        {

            WindsorContainer container = new WindsorContainer(new XmlInterpreter());

            ICommerceService service = container.Resolve<ICommerceService>("mockCommerceService");

 

            Assert.AreEqual("9.99", service.GetPrice("The Shins - Chutes Too Narrow"));

        }

 

        /// <summary>

        /// Determines whether this instance can successfully interact with a live commerce service.

        /// </summary>

        [Test]

        public void CanQueryCommerceService_Live()

        {

            WindsorContainer container = new WindsorContainer(new XmlInterpreter());

            ICommerceService service = container.Resolve<ICommerceService>("liveCommerceService");

 

            Assert.AreEqual("99.99", service.GetPrice("The Shins - Chutes Too Narrow"));

        }

    }



Notice that in both cases that we are using the Windsor Container as an abstract factory to create the specific implementation of ICommerceService that we desire.  Let's step through the code...
The first thing we need to do is to create an instance of the WindsorContainer using an XmlInterpreter. 

WindsorContainer container = new WindsorContainer(new XmlInterpreter());


This should give you a slight hint as to what's going on under the covers...we'll be using our app.config file in order to load the types that we need at runtime.
Next, we use the container to dynamically resolve our type depending on the implementation that we need...

ICommerceService service = container.Resolve<ICommerceService>("mockCommerceService");

 

There are two things to notice about the container.Resolve<>() method.  First, this is a generic method so we simply have supply the type, or base type, that we intend to create as a type parameter.  Second, this constructor takes an optional string specifying the ID of the specific implementation that we wish to create.  Remember, this is an optional parameter, if we don't supply an ID then Windsor simply instantiates the first type of the given base type that it finds in the config file.


Speaking of the config file, as you've probably guessed from the presence of the XmlInterpreter class, the WindsorContainer finds out what it needs to know from the app.config file. 

Let's take a look at it...

<?xml version="1.0" encoding="utf-8" ?>

<configuration>

  <configSections>

    <section name="castle"

            type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor"/>

  </configSections>

  <castle>

    <components>

      <component id="mockCommerceService" service="ServiceLayer.ICommerceService, ServiceLayer"

                type="ServiceLayer.MockCommerceService, ServiceLayer"/>

      <component id="liveCommerceService" service="ServiceLayer.ICommerceService, ServiceLayer"

                type="ServiceLayer.CommerceService, ServiceLayer"/>

    </components>   

  </castle

</configuration>


The config file has two sections that we're interested in.  First, notice that that we're adding a section of type "castle" in the conifgSections node.  This is simply how we tell .NET that we'll be handling a custom configuration section.  We only need to supply the name of the node and the type that we'll be using to handle it.

Next, we have the castle section itself.  This node simply has a 'components' node which contains an element for each type we're planning to instantiate.  These nodes,  called component nodes,  have three key parts:  an id, a service, and a type.  The id is how we specify the component from code.  Remember the string in the Resolve<>() method from the example above?  This is the ID we were talking about.  If we hadn't supplied an ID to the Resolve() method, Windsor simply would have instantiated the mockCommerceService component because it's the first component found in the file.  Next up, we have the service attribute.  The service attribute specifies the base type, or interface, that this particular component is implementing as well as the name of the assembly that it can be found in.  Finally, we specify the type itself.  The type is the actual concrete implementation of the component as well the name of the assembly that it is found in.  Notice that in our example, both components specify the same value for service but different values for type.  This is because we're actually offering two different implementations of the same interface...hence, the power of IoC containers.

That's it!  You can download the code from here, note that you'll need the Castle Project installed to be able to reference the assemblies from the GAC.  This introduction is only the tip of the iceberg of even some of the simplest scenarios you can accomplish with the Windsor Container.  For an excellent deeper dive into Windsor, check out Bitter Coder's series of tutorials here, which have been conveniently collected into one place by Insane World.

kick it on DotNetKicks.com

Feedback

# re: Windsor IoC Container in a Lunch Break

Cool. I like it. So I take it the idea here is I can specify which components to use at runtime by simply altering my app.config. It's like a generic factory that learns what it's serving from the config file. Cuz in the example you can obviously quite easily just directly isntantiate a mock or real service as needed.

btw, you list the code for the real service twice :) 7/23/2007 1:19 PM | Matt

# re: Windsor IoC Container in a Lunch Break

Yup, that's exactly it! Think of it like this, if you don't supply a string to the Resolve() method you can use the exact same code whether your testing or in production. You would simply provide a separate config file for each scenario. The config file for the testing scenario would reference your mock object whereas the config file for your production scenario would reference your live service.

By the way, thanks for the hint about the commerce service being listed twice. I fixed it in the article :) 7/23/2007 1:28 PM | Jeremy

# New and Notable 179

Ever hear the story of the guy who responded to ScottW&amp;#39;s Facebook NJ Developers and DonXML &amp;#39;s 7/24/2007 9:16 AM | Sam Gentile

# re: Windsor IoC Container in a Lunch Break

Very nice. Just one thing: the MSI only installs two assemblies on the GAC. To present on the Add References dialog on VS.Net we just add a registry entry (on AssemblyFoldersEx) 7/24/2007 11:01 AM | hammett

 re: Windsor IoC Container in a Lunch Break

I would like to see what structure people use for unit testing their assemblies while using IOC. I would think you would want a separate config file for unit testing, but I can see how that might bet messy. I guess I should just play around with it and see what I can figure out.

Did you evaluate the other IOC frameworks? Any preference?
7/24/2007 11:42 AM | DM

# re: Windsor IoC Container in a Lunch Break

DM, we never use the IoC on test cases around here. The reason is, among other things, to not have to deal with configurations, but also to keep the test self contained. 7/24/2007 1:04 PM | hammett

# re: Windsor IoC Container in a Lunch Break

@hammett

Thanks for the clarification regarding the GAC assemblies versus the Add Reference dialog. That registry key thing has always been a big gotcha for me when writing installers for APIs.

Congratulations on a great project, every piece of the Castle project seems to be absolutely top notch. You guys should all be very proud! 7/24/2007 1:37 PM | Jeremy

# re: Windsor IoC Container in a Lunch Break

DM,

Thanks for the comment. In regards to the config files I'll typically use a different config with the test assembly then the production code. It's a habit (possibly bad) that I picked up from running unit tests against a test database and developing against a different database. I'll also be the first to admit that you're entirely right...it gets very messy and possibly is not the optimal solution. I do tend to use IoC in testing but not exactly Iike I did here in the examples. I typically push the IoC down a layer into factories and work with them from there. Then I just swap out the default configurations. Once again, probably not the ideal solution and Hammet brought up some really good points in his comment as well about keeping the test self contained.

Hope this helps! 7/24/2007 1:43 PM | Jeremy

# re: Windsor IoC Container in a Lunch Break

DM,

Also, I just realized I forgot to respond to your question regarding other frameworks. Actually no, Windsor is the only one I've looked at. I picked it on a whim based solely on the reputation of the castle project. I've never heard much about Spring.NET but I have heard a lot of good things about Structure Map. As a matter of fact, Derik Whittaker just published a great brief tutorial showing you how to do this exact same thing with Structure Map and Rhino.Mocks. Here's the URL if you're interested: http://devlicio.us/blogs/derik_whittaker/archive/2007/07/24/using-rhinomocks-with-structuremap-to-mock-expected-calls.aspx 7/24/2007 1:49 PM | Jeremy

# re: Windsor IoC Container in a Lunch Break

I've been trying to wrap my head around Castle a bit, this post is a great how-to. Here's a question for you: If I have multiple classes that implement an interface, I have to pass the ID of which to pick in the code itself. At this point what flexibility is this container buying me? Seems like I am explicitly hardcoding a choice right in the code, just by id passed to Castle rather than a class name. It not the intention that I keep the same ids but switch their values in the config file later on as that would be nuts right? 7/26/2007 2:47 PM | Mike Duncan

# re: Windsor IoC Container in a Lunch Break

Mike, you don't need to supply the ID. Windsor will inject the first implementation of the service registered in the container. 7/26/2007 4:19 PM | SimoneB

# re: Windsor IoC Container in a Lunch Break

SimoneB , maybe I'm not understanding something obvious, but isn't it the case that all of my services get registered in one big block in the xml? What I'm asking is if I *dont* want the first one, I'll have to hard code the ID in my code wont I? If that was the case then Castle would only seem to be worthwhile for cases where you were going to use the default implementation. In the case that multiple registered services implement an interface like in this example, arent I still hard-coded in approximately the same way in my c#? 7/26/2007 4:51 PM | Mike Duncan

# re: Windsor IoC Container in a Lunch Break

Mike, if you are registering multiple implementations for services they are probably being used by some other classes, either via constructor or setter injection. Then you'll end up having a facade or something like that that makes use of your components. Usually that class won't have multiple implementations, so you can retrieve it from the container with no need to specify its key, and its dependencies are managed by the container either with the default first registered-first injected rule or by using the syntax ${componentId}. I suggest you read Windsor docs to get an idea of all this stuff. I don't aim at advertising my own stuff but a series of articles about Windsor which covers most of the core concepts is being published on DotNetSlackers. 7/26/2007 5:41 PM | SimoneB

# re: Windsor IoC Container in a Lunch Break

Mike,

Thanks for the interest. I just wanted to mention that I've recently started reading the articles the Simone mentions on DotNetSlackers and they're really top notch. I would fully recommend them for a deeper look into some of the core concepts of Windsor. I've provided the link here for ease:
http://dotnetslackers.com/articles/designpatterns/InversionOfControlAndDependencyInjectionWithCastleWindsorContainerPart1.aspx

Jeremy 7/26/2007 9:28 PM | Jeremy

# re: Windsor IoC Container in a Lunch Break

Incidentally my container tutorials are already collected in on place on my wiki, which is probably more authoritative then Casey's (insaneworlds) post - there are plans to release some more content covering some of the deeper stuff in the windsor container / microkernel too.

http://wiki.bittercoder.com/ContainerTutorials.ashx

Nice job, keep up the good work! 7/31/2007 6:24 PM | Alex Henderson

Post a comment





 

Please add 3 and 6 and type the answer here: