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

You got Boo in my Windsor!!!

Sunday, October 07, 2007 12:04 PM
Like peanut butter and chocolate, two of my favorite technologies have finally been brought together in a marriage of sweet technology love.  Actually, "finally" may a bit of an understatement since this apparently happened over a year ago and I was just completely oblivious.

What am I speaking of?  "Binsor".  Binsor combines the power of the Windsor IoC framework, with the clear and concise expressability of the Boo programming language.

Not many people would argue the value of Windsor as a lightweight IoC framework, but the complexity of XML configuration is a difficult point to ignore.  In fact, this added complexity can often be the breaking point which prevents teams from using a framework such as Windsor, and thus embracing the full power of Inversion of Control.  That's where Binsor comes in.  Binsor is effectively an add-on to Windsor which allows you to specify the relationship between the interfaces and concrete classes using the concise elegance of the programming language Boo instead of the angled clunkiness of XML.

Let's take a look...

This is how you would instantiate the proper class in code, using traditional Windsor...

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

And this is how you define the relationship between the interfaces and co-classes using XML...

<?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>

Not very pretty is it?  Let's see how it looks with Boo.   Here's how you instantiate the classes in code using the new BooReader class...
            IWindsorContainer container = new RhinoContainer("CommerceService.boo");

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


With the exception of the RhinoContainer class in place of the WindsorContainer  and the reference to "CommerceService.boo", this is almost the exact same code.  There are no real changes here thanks to the power of interfaces.
Let's look at how we would specify the service...

import ServiceLayer

liveCommerceService = Component("liveCommerceService", ServiceLayer.ICommerceService, ServiceLayer.CommerceService)
mockCommerceService = Component("mockCommerceService", ServiceLayer.ICommerceService, ServiceLayer.MockCommerceService)

Simple enough.  We basically create an instance of Component with three arguments:  the key to be specified in the Resolve() method, the fully qualified path name of the interface our component will implement, and the fully qualified path name of the concrete class which will implement our component.  This is clear, concise, and definitely a lot shorter than the our previous XML file.  If you want to add more implementations then simply add more lines to the .boo file.  And just like with the original Windsor, if you want to omit the name of the service to instantiate, Binsor will simply return the first implementation it finds in the file.

I've included a sample application to help you get started.  Attentive readers will recognize this example from my Windsor in a Lunch Hour example a few weeks ago.  You may want to take a look at both examples to get a better idea of the differences.  Also, there's one small gotcha with Binsor:  As the .boo file is read at runtime, it'll need to be accessible from the assemblies.  Therefore you'll want to ensure that it is always copied to the output directory.  You can do this by highlighting the .boo file in the Solution Explorer, right-clicking it and selecting Properties and setting the value of "Copy to Output Directory" to "Copy always".  This will ensure that the file is always on disk where the assemblies can get to it. 

kick it on DotNetKicks.com

Feedback

# re: You got Boo in my Windsor!!!

Question. Is there any reason why you couldn't embed the .boo file as an embedded resource file and have it read directly from the assembly? That just seems a little cleaner to me from a deployment standpoint. Is there one? I'm just asking since I am nowhere near close to the Windsor project. 10/15/2007 5:15 PM | Keith Elder

# re: You got Boo in my Windsor!!!

Great idea, Keith! That thought had actually crossed my mind as well but I hadn't gotten around to trying it. Here's a new post that dives into exactly what you mentioned...

http://www.jeremyjarrell.com/archive/2007/10/16/63.aspx 10/17/2007 8:36 AM | Jeremy

# re: You got Boo in my Windsor!!!

Ta for the example, when I tried to play with Binsor on my own there I just got annoying errors and eventually worked out that it didn't like "Binsor" being in my assembly name.

Have to say it would be a lot better if Boo had a Visual Studio integration. 3/21/2008 6:07 PM | Colin Jack

Post a comment





 

Please add 5 and 7 and type the answer here: