Thursday, October 19, 2006

I think there's 3 levels of skill involved with the Castle IoC implementation... first off you get a handle of the XML configuration, registering components, using existing facilities... pretty much getting away largely with cut 'n paste coding.

Then you get to the intermediate level.. writing basic facilities, tweaks to the component model, writing your own sub dependency resolvers or component activator, having a go with binsor configuration.

I think the third level is reserved for the Castle team alone... ;o)

This post is going to be straddling the beginner to intermediate kinda level... which is generally all I ever reach with Castle's IoC... it's not often you have to dig deeper day-to-day... though it's always good to know there is a lot of untapped potential there.

So.. for today, say you have a component, like the Base4Host, which has some explicit constructors:

public Base4Host(string appName, int port)

{

    if (string.IsNullOrEmpty(appName)) throw new ArgumentNullException("appName");

    if (port <= 1024) throw new ArgumentOutOfRangeException("port", "port should be greater then 1024");

    _appName = appName;

    _port = port;

}

 

public Base4Host(string appName, int port, string root)

    : this(appName, port)

{

    if (string.IsNullOrEmpty(root)) throw new ArgumentNullException("root");           

    _root = root;

}


You can register it the container easy enough, and provide values for them in XML configuration, but what if you want to do the same programatically... generally your first stop would be to examine the IWindsorContainer for a suitable overload... alas it doesn't get us far, so we dig in to the underlying IKernel itself... the kernel exposes some possible candidates:

void AddComponentWithExtendedProperties(String key, Type classType, IDictionary extendedProperties);

void AddComponentWithExtendedProperties(String key, Type serviceType, Type classType, IDictionary extendedProperties);


So you experiment with them, but supplying the dictionary of extended properties does nothing... hmm... time to file a bug report? well no... extended properties having nothing to do with satisfying parameter or property dependencies on your component - not directly at least.

So why don't we just create the component ourselves.. and then add it to the container?

Well you can, via the Kernel.AddComponentInstance method but you're going to miss out on some things... for instance the startable facility won't be "concerned" with your component, and as such if it implements IStartable it won't get started and stopped... Though I haven't confirmed this, I dont think the container will bother to dispose of any IDisposable components registered in this fashion either... the container doesn't consider itself the owner of the component (and generally this is what we want).

So we're going to have to get a little more intimate with the container implementation ... so every time a component is registered in the container a corresponding ComponentModel is generated for the component, this basically keeps track of the:
  • Components dependencies
  • Constructor candidates
  • Parameters (sounds like us...)
  • Name, implementation type and service type.
  • Lifecycle, Lifestyle...
  • And some other stuff you can discover for yourself.
Now we could get heavy handed and jump into contributing to the construction of the component model itself... but it's pretty uncessary, we just want to tweak the end result... so we can use an event handler on the Kernel - ComponentModelCreated.

So here we have an implementation that solves our problems... This is being implemented inside a facility, but you could do this anywhere... wire it up in your custom container that's derived from WindsorContainer maybe, obviously you want to remove the if statement for checking the Implemenation type is Base4Host though. :)

private const string AdditionalParametersKey = "AdditionalParameters";

 

private void Kernel_ComponentModelCreated(Castle.Core.ComponentModel model)

{

    if (model.Implementation == typeof(Base4Host))

    {

        if ((model.Configuration == null)

            && model.ExtendedProperties.Contains(AdditionalParametersKey))

        {

            Dictionary<string, object> additionalParameters = (Dictionary<string, object>)model.ExtendedProperties[AdditionalParametersKey];

            foreach (string parameterName in additionalParameters.Keys)

            {

                model.Parameters.Add(parameterName, Convert.ToString(additionalParameters[parameterName]));

            }

        }

    }

}

 

protected override void Init()

{

    Kernel.ComponentModelCreated += new ComponentModelDelegate(Kernel_ComponentModelCreated);

}


Now I can register my component by doing something like this:

Dictionary<string, object> additionalParameters = new Dictionary<string, object>();

additionalParameters.Add("appName", _applicationName);

additionalParameters.Add("port", _port);

additionalParameters.Add("root", _baseDirectory);

 

Hashtable properties = new Hashtable();

properties.Add(AdditionalParametersKey, additionalParameters);

 

Kernel.AddComponentWithProperties("base4.defaultHost", typeof(Base4Host), properties);


Here we're passing all our additional parameters as a Dictionary<string, object> inside our IDictionary of additional properties....  this isn't the most elegant implementation, but this is all code internal to a single facility so it's not really important to me... and it gets the job done just fine.


posted @ Wednesday, October 18, 2006 8:46:17 PM (New Zealand Daylight Time, UTC+13:00)    Comments [2] | Trackback |
Thursday, October 19, 2006 3:49:23 AM (New Zealand Daylight Time, UTC+13:00)
IoC is looking increasingly cool man, if I didn't have a mortgage I would beg you to work for free on your projects so I use it daily =)

I found Windsor on http://devlicio.us/blogs/christopher_bennage/archive/2006/10/18/Your-Development-Tools.aspx, and remembered you mentioning that you have used this previously, and here you are blogging it =)
Nikolai
Thursday, October 19, 2006 7:26:18 AM (New Zealand Daylight Time, UTC+13:00)
Yeah, been using it for a year and a half now... it's grown into a very robust IoC implementation over that period, the generics support added by Ayende (http://www.ayende.com/Blog/) is fantastic too... you can do some very cool things :)

Leaves the the Microsoft Patterns & Practice's teams "attempt" at inversion of control in the dust.
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