Registering components on Windsor, the cool way

February 25th, 2008

Craig Neuwirt (no blog), one of the oldest Castle committers (I mean, he has been involved for a long time!) created a sweet way to register components on Windsor. I’ve been planning to blog about it for a long time, but I wanted to get some experience with it before.

So we basically provide this old fashioned family of methods:

AddComponent
AddComponentLifeStyle
AddComponentWithProperties

The AddComponentWithProperties is mislead. It means that you’re going to provide the custom properties for the components, those that are used by facilities and/or subsystems. Not the actual properties of the implementation.

Now, Craig added a simple Register method. The magic happens on the build you pass to the Register method:

container.Register( Component.For<IMyServiceContract>().ImplementedBy<MyServiceImpl>() );

As the Register accepts an array (with ParamArray attribute), you can use to make multiple registrations:

container.Register( 
    Component.For<IMyServiceContract>().ImplementedBy<MyServiceImpl>(), 
    Component.For<IMyOtherServiceContract>().ImplementedBy<MyServiceImpl>(), 
    Component.For<IMyKewlServiceContract>().ImplementedBy<MyServiceImpl>(), 
    Component.For<IMyNeatServiceContract>().ImplementedBy<MyServiceImpl>(), 
    Component.For<IMySweetServiceContract>().ImplementedBy<MyServiceImpl>()
);

I’m sure you want more. And you got it. The Component.For creates a ComponentRegistration instance. See its source to see that it does everything you can do through external configuration.
http://svn.castleproject.org:8080/svn/castle/trunk/InversionOfControl/Castle.MicroKernel/Registration/ComponentRegiatration.cs

More examples:

Specifying the name and a lifestyle:

container.Register( Component.For<IMyServiceContract>().
	Named("my.component").
	ImplementedBy<MyServiceImpl>().
	LifeStyle.PerThread
);

Adding a custom instance

container.Register( Component.For<IMyServiceContract>().
	Instance(new MyServiceImplementation() )
);

Setting up parameters:

container.Register( Component.For<IEmailSender>().
	ImplementedBy<SmtpEmailSender>().
	Parameters(
		Parameter.ForKey("host").Eq("my.smtp.host.name"), 
		Parameter.ForKey("port").Eq("155") )
);

Setting up service overrides:

container.Register( Component.For<ISpamSender>().
	ImplementedBy<MySpamSender>().
	ServiceOverrides(
		ServiceOverride.ForKey("emailSender").Eq("smtpsender") )
);

Now, the only weakness left to cover on Windsor is the damn Component Burden. Once it’s done, we’re ready to 1.0.

16 Responses to “Registering components on Windsor, the cool way”

Bill Pierce Says:

You’ve been beating that Component Burden drum for a long time. I am starting to wonder if it really exists :)

hammett Says:

It does. I’ve coded it in a very old container I have created when I was on Apache Avalon, or Excalibur, can’t remember. But I really dislike that implementation, and have been looking for a better one since then.

Four years have passed!!

Bruno Fiorentino Says:

Really cool.
It´s familiar with jQuery and Db4o (SODA query) API. It could be a pattern…

Tuna Toksoz Says:

It is fluent interfaces, isn’t it?

hammett Says:

Right!

Bruno Fiorentino Says:

I think you are right: http://en.wikipedia.org/wiki/Fluent_interface
The LINQ API follow this approach to some extent (when using LINQ´s extension methods without all that sintax sugar).

Tuna Toksoz Says:

At least, we can live long enough to see RC4 :)
I am just kidding :)

Jeremy Gray Says:

Now, if only we could get rid of the magic strings passed to ForKey, perhaps through a bit of expression tree magic. :)

hammett Says:

Jeremy, long time no see.

Jeremy Gray Says:

Long time lurker, only occasional poster. ;)

Torkel Says:

Can you explain the Component Burden concept? I googled it and found only the Castle JIRA issue which did not really describe it.

hammett Says:

Will do.

Craig Neuwirt Says:

I just committed some changes that add an IRegistration interface. The ComponentRegistration is just an implementation of that. This will allow the encapsulation of other common registration strategies that do more specialized registrations. A common usage would be to register all Controllers in one or more assemblies satisfying one or more predications

e.g
kernel.Register( AllTypes
.FromAssembly( “MyProject.Web” )
.FromAssembly( “MyExtensions.Web )
.WithAttribute()
.With( t => t.GetName().StartsWith( “Foo” )
);

I will be adding these generlized registrations shortly.

Colin Jack Says:

Nice looking stuff.

Leo Staalman Says:

Thanks for the cool stuff Craig, and the good samples Hammett. But I have one question left: What is(/are) the best spot to put this? Say I have an Website with all business stuff in separate assemblies. And unit tests for the business layer per assembly. One assembly with all ‘pluggable’ interfaces like ILogger. And assemblies that contain the concrete implementations. Should there be one assembly that contains all of the register code, and that knows of the assembly that define the interfaces and the assemblies that contain concrete implementations? Or can/should the register code be decentralised somehow? Must the registering assembly be reference by the business layer, or is it only referenced by the website and unittest, so the business layer does not know anything about this?
Thanks,
Leo

Nico Says:

And if i want to add a parameter array ? Or a parameter list ?
e.g:
<component …
<parameters>
<array>
<item></item>
<item></item>
</array>
</parameters>
</component>

Leave a Reply