Dashboard > MicroKernel/Windsor > Home > Strongly Typed property wiring with Fluent Registration API
Log In   View a printable version of the current page.
Strongly Typed property wiring with Fluent Registration API
Added by Alwin, last edited by Alwin on Dec 11, 2008  (view change)
Labels: 
(None)


This is a tip for strongly typing the wiring component wiring. This only works with properties. It uses .NET 3.5 / C# 3.0.

This is a way to make the component registration more refactoring friendly, and gets rid of evil strings.

The idea is to use an Expression to get the property info, and then use the name of that info.

See the Typed_dependencies_will_wire test for example hot to use this.

The test fixture:

[TestFixture]
public class PropertyDependenciesTests
{
	private IWindsorContainer container;

	[SetUp]
	public void SetUp()
	{
		container = new WindsorContainer();

		container.Register(
			Component.For<IService>().ImplementedBy<FirstServiceImpl>().Named("first"),
			Component.For<IService>().ImplementedBy<SecondServiceImpl>().Named("second")
			);
	}

	/// <summary>
	/// Also example for how to use typed dependencies.
	/// </summary>
	[Test]
	public void Typed_dependencies_will_wire()
	{
		container.Register(
			Component.For<ComponentWithProperties>()
				.ServiceOverrides(
					ServiceOverride<ComponentWithProperties>.ForProp(x => x.ServiceDependency).Eq("second")
				).DependsOn(
					Property<ComponentWithProperties>.ForProp(x => x.StringParameter).Eq("Typed dependencies!")
				)
			);

		var component = container.Resolve<ComponentWithProperties>();

		component.StringParameter.should_be_equal_to("Typed dependencies!");
		component.ServiceDependency.should_be_an_instance_of<SecondServiceImpl>();
	}

	[Test]
	public void Untyped_dependencies_will_wire()
	{
		container.Register(
			Component.For<ComponentWithProperties>()
				.ServiceOverrides(
					ServiceOverride.ForKey("ServiceDependency").Eq("second")
				).DependsOn(
					Property.ForKey("StringParameter").Eq("Typed dependencies!")
				)
			);

		var component = container.Resolve<ComponentWithProperties>();

		component.StringParameter.should_be_equal_to("Typed dependencies!");
		component.ServiceDependency.should_be_an_instance_of<SecondServiceImpl>();
	}

	[Test]
	public void Check_default_values()
	{
		container.Register(Component.For<ComponentWithProperties>());

		var component = container.Resolve<ComponentWithProperties>();
		component.ServiceDependency.should_be_an_instance_of<FirstServiceImpl>();
		component.StringParameter.should_be_null();
	}
}

The test components:

public class ComponentWithProperties
{
	public string StringParameter
	{
		get;
		set;
	}

	public IService ServiceDependency
	{
		get;
		set;
	}
}

public interface IService
{
}

public class FirstServiceImpl : IService
{
}

public class SecondServiceImpl : IService
{
}

The strongly typed Property and ServiceOverride classes:

namespace Castle.MicroKernel.Registration
{
	public class Property<C>
	{
		public static PropertyKey ForProp(Expression<Func<C, object>> property)
		{
			var name = Reflect<C>.GetProperty(property).Name;
			return Property.ForKey(name);
		}
	}
}

namespace Castle.MicroKernel.Registration
{
	public class ServiceOverride<C>
	{
		public static ServiceOverrideKey ForProp(Expression<Func<C, object>> property)
		{
			var name = Reflect<C>.GetProperty(property).Name;
			return ServiceOverride.ForKey(name);
		}
	}
}

Reflect<C> is made by Daniel Cazzulino. Please get it from here:
http://netfx.googlecode.com/svn/trunk/Source/Reflection/Reflect.cs
More info on Reflect<C>:
http://netfx.googlecode.com
http://www.clariusconsulting.net/blogs/kzu/archive/2007/12/30/49063.aspx

Also it is possible to get rid of naming ( .Named ).
This extension exploits the fact that the default key that windsor assignes is a full name of the implementation.

public static ServiceOverride With<T>(this ServiceOverrideKey overrideKey)
{
   return overrideKey.Eq(typeof(T).FullName);
}

//ServiceOverride<ComponentWithProperties>.ForProp(x => x.ServiceDependency).Eq("second")
// changes to
ServiceOverride<ComponentWithProperties>.ForProp(x => x.ServiceDependency).With<SecondServiceImpl>()
Site running on a free Atlassian Confluence Community License granted to Castle Project. Evaluate Confluence today.
Powered by Atlassian Confluence, the Enterprise Wiki. (Version: 2.5.4 Build:#809 Jun 12, 2007) - Bug/feature request - Contact Administrators