Home >

Implementing EnrichWith(of StructureMap) with Castle

15. July 2009

UPDATE: This facility made its way into Castle Microkernel, with name OnCreateFacility. I also made it possible to specify more than one actions.

In one of Joshua Flanagan's recent post he mentioned about how they handle application configuration and I have to say that I liked their way. I also liked how SM can post-modify an object created, and looked for a way to do it in Castle. As many other stuff, I was able to achieve the same effect with a custom Facility.

If I go further in the details, I had to catch ComponentCreated event of Kernel.

public class EnrichWithFacility:AbstractFacility
{
	public const string ExtendWithPropertyKey = "extendwith";
	protected override void Init()
	{
		Kernel.ComponentCreated += Kernel_ComponentCreated;
	}
	void Kernel_ComponentCreated(ComponentModel model, object instance)
	{
		if(model.ExtendedProperties.Contains(ExtendWithPropertyKey))
		{
			var action = model.ExtendedProperties[ExtendWithPropertyKey] as ExtendComponentDelegate;
			action(this.Kernel, instance);
		}
	}
}

Whenever a component is created, I will catch it and ask if there is any EnrichWith registered for the ComponentModel, and if there is any, invoke the action.

I also added a fluent registration extensions (Castle style!) in order to make it easy to register enrichments.

container.Register(Component.For<IService>().ImplementedBy<MyService>()
			 .EnrichWith((kernel, instance) => ((IService) instance).I++));

 

The code for the facility, fluent registration interface,and the tests can be found on our never-ending blog engine, BlogSharp codebase.

, ,

Comments

7/15/2009 1:53:35 AM #
This is a nice addition, and it should be in the core framework. Why the heck do you have to cast instance to the IService? It should be inferred from generic parameter of For<T>()
7/15/2009 1:57:21 AM #
There will be a problem with casting.

var action = model.ExtendedProperties[ExtendWithPropertyKey] as ExtendComponentDelegate;

We don't know the generic type here, it can be taken from the Component model and then we can invoke typeof(ExtendComponentDelegate<>).MakeGenericType() etc but didn't want to make it ugly.
7/15/2009 2:09:07 AM #
ha!

Long live generic variance ay?

You could keep this not as delegate but as simple wrapper generic class with not generic base type

public abstract class AbstractWrapper
{
public abstract void Invoke(IKernel kernel, object component);
}

public class Wrapper<T>:AbstractWrapper
{
private FooDelegate<T> method;//set in the ctor by the EnrichWith impl.

public void Invoke(IKernel kernel, object component)
{
   method(kernel, (T)component);
}
}

you create derived class instances, but refer to them via base type.

Should work.
7/15/2009 3:31:06 AM #
I like it. Another reason to use the Castle stack on my next project.. and maybe StructureMap too.

Add comment


(Will show your Gravatar icon)

  Country flag

biuquote
  • Comment
  • Preview
Loading