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.
February 25th, 2008 at 11:27 am
You’ve been beating that Component Burden drum for a long time. I am starting to wonder if it really exists
February 25th, 2008 at 11:44 am
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!!
February 25th, 2008 at 1:29 pm
Really cool.
It´s familiar with jQuery and Db4o (SODA query) API. It could be a pattern…
February 25th, 2008 at 2:01 pm
It is fluent interfaces, isn’t it?
February 25th, 2008 at 2:06 pm
Right!
February 25th, 2008 at 2:08 pm
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).
February 25th, 2008 at 2:54 pm
At least, we can live long enough to see RC4

I am just kidding
February 25th, 2008 at 7:50 pm
Now, if only we could get rid of the magic strings passed to ForKey, perhaps through a bit of expression tree magic.
February 25th, 2008 at 7:57 pm
Jeremy, long time no see.
February 25th, 2008 at 8:27 pm
Long time lurker, only occasional poster.
February 26th, 2008 at 4:29 am
Can you explain the Component Burden concept? I googled it and found only the Castle JIRA issue which did not really describe it.
February 26th, 2008 at 7:43 am
Will do.
February 28th, 2008 at 11:14 pm
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.
March 23rd, 2008 at 4:57 pm
Nice looking stuff.
April 24th, 2008 at 4:29 am
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
November 3rd, 2008 at 12:55 pm
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>