Tom Marien bio photo

Tom Marien

Passionate .NET/Node Developer, Team Leader, living in Belgium

Email Twitter LinkedIn Github Subscribe

In my previous post, I showed you how to register and resolve the most basic components.

  • But how can we resolve Func or Lazy ?
  • What’s up with facilities ? What are they and how to use them.

I will briefly touch one of many facilities available for Castle Windsor: TypedFactoryFacility.

Overview

Array[T] - IEnumerable - IList - ICollection

What if one of your components depend on an array or a IEnumerable. Consider following scenario:

public class TaskExecutorWithArray
{
	private readonly ITask[] tasks;
	public TaskExecutorWithArray(ITask[] tasks)
	{
		this.tasks = tasks;
	}
}

In Castle Windsor you need to opt-in for this behavior before registering components, so the container knows you want this behavior.

// Initialize the container
var container = new WindsorContainer();
// Important opt-in for this behavior before registering components !
container.Kernel.Resolver.AddSubResolver(
                                new CollectionResolver(container.Kernel, true));
// Register components
container.Register(Component.For<ITask>().ImplementedBy<FirstTask>());
container.Register(Component.For<ITask>().ImplementedBy<SecondTask>());
container.Register(Component.For<TaskExecutorWithArray>());
// Resolve our array
TaskExecutorWithArray executor= container.Resolve<TaskExecutorWithArray>();

This will work if your TaskExecutor is depending on an IEnumerable, ICollection, IList or an array of ITask. The second constructor parameter of CollectionResolver determines if Windsor allows empty collections, so if the value is true it will not throw an exception if you have no components registered.

You need to opt-in before registering any components otherwise it will not work!

CollectionResolverFacility

As this does not exist out of the box and it is so important to opt-in before registering any components, let’s create our first facility. A facility is more or less an extension of Castle.Windsor.

using Castle.Core.Configuration;
using Castle.MicroKernel;
using Castle.MicroKernel.Resolvers.SpecializedResolvers;
namespace Windsor.Tests.Facilities
{
   public class CollectionResolverFacility : IFacility
   {
      public void Init(IKernel kernel, IConfiguration facilityConfig)
      {
         kernel.Resolver.AddSubResolver(new CollectionResolver(kernel, true));
      }
      public void Terminate() {}
   }
}

Now next time you need to have collection dependencies you will just need to add the facility to Windsor like this:

// Initialize the container
var container = new WindsorContainer();
// Add the facility to the container before adding any component registrations !
container.AddFacility<CollectionResolverFacility>();

Func

What if you needed to resolve a Func ? You could just do this, albeit a little bit cumbersome:

// Initialize the container
var container = new WindsorContainer();
// Register your component
container.Register(Component.For<ITask>().ImplementedBy<FirstTask>());
// Now register your delegate as a factory
container.Register(Component.For<Func<ITask>>()
                            .UsingFactoryMethod(
                                  kernel => new Func<ITask>(kernel.Resolve<ITask>)));
// Now you can resolve your func
Func<ITask> taskFunc = container.Resolve<Func<ITask>>();

What if you wanted this behavior out of the box without registering every delegate by hand: use the power of TypedFactoryFacility:

// Initialize the container
var container = new WindsorContainer();
// Add the facility
container.AddFacility<TypedFactoryFacility>();
// Register your component(s)
container.Register(Component.For<ITask>().ImplementedBy<FirstTask>());
// Now you can resolve a func for every component you registered !
Func<ITask> taskFunc = container.Resolve<Func<ITask>>();

Lazy

Last but not least how to use Lazy, a recent addition to Castle Windsor (as of version 3)

// Initialize the container
var container = new WindsorContainer();
// Opt-in for this behavior
container.Register(Component.For<ILazyComponentLoader>()
                            .ImplementedBy<LazyOfTComponentLoader>());
// Register your component
container.Register(Component.For<ITask>().ImplementedBy<FirstTask>());
// Now resolve your Lazy<ITask>
Lazy<ITask> lazyTask = container.Resolve<Lazy<ITask>>();

Next time i will try to elaborate on the trough power of the TypedFactoryFacility, i hope you are liking the series so far. Remember your feedback is important!