Castle Windsor - resolve dependencies on an existing object instance

Print Content | More

Being able to configure an existing object resolving all its dependencies sometimes can be useful, but it can indeed be dangerous because you are mixing two different techniques of creating and managing objects lifecycles, I will not discuss why this can be troublesome, because it’s a very long and complex discussion to do in this short blog post.

Nonetheless it happened in a couple of situation that I needed to configure an already existing instance of an object, but Castle Windsor doesn’t have direct support for this scenario (Unity has a Buildup() function to do the job).

The easiest thing you can do is rely on Reflection to cycle through all your properties and ask the container to resolve the dependencies; here are a couple of extension methods that work well for me (they can be further extended to cover some more cases):

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Castle.MicroKernel.Resolvers.SpecializedResolvers;
using Castle.Windsor;

public static class Extensions
{
	/// <summary>
	/// Determines whether the specified type is a generic collection.
	/// </summary>
	/// <param name="type">The type.</param>
	public static bool IsGenericCollection(this Type type)
	{
		if (type == null)
		{
			throw new ArgumentNullException("type");
		}
		return type.GetInterfaces().Where(@interface => @interface.IsGenericType).Any(@interface => @interface.GetGenericTypeDefinition() == typeof(ICollection<>));
	}

	/// <summary>
	/// Adds the CollectionResolver to the container.
	/// </summary>
	/// <param name="container">The container.</param>
	/// <param name="allowEmptyCollections">if set to <c>true</c> [allow empty collections].</param>
	public static void AddCollectionResolver(this IWindsorContainer container, bool allowEmptyCollections)
	{
		container.Kernel.Resolver.AddSubResolver(new CollectionResolver(container.Kernel, allowEmptyCollections));
		_useCollectionResolver = true;
	}

	/// <summary>
	/// I havent found an easy way to check if a SubResolver was added to the kerner, so just register it through our extension method and
	/// use a static bool variable to do the check
	/// </summary>
	private static bool _useCollectionResolver;

	public static void ResolveDependencies(this IWindsorContainer container, object objToConfigure)
	{
		// get all the properties through reflection
		PropertyInfo[] props = objToConfigure.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
		foreach (var info in props)
		{
			object o = info.GetValue(objToConfigure, null);
			// skip the object is it already contains a value of any sort
			if (o != null) continue;
			if (_useCollectionResolver && info.PropertyType.IsGenericCollection())
			{
				o = container.ResolveAll(info.PropertyType.GetGenericArguments()[0]);
			}
			else if ((info.PropertyType.IsInterface) || (info.PropertyType.IsClass))
			{
				// try to resolve the related type if the component knows it
				if (container.Kernel.HasComponent(info.PropertyType))
					o = container.Resolve(info.PropertyType);
			}
			if (o != null)
				info.SetValue(objToConfigure, o, null);
		}
	}

	public static void ReleaseDependencies(this IWindsorContainer container, object objToConfigure)
	{
		// get all the properties through reflection
		PropertyInfo[] props = objToConfigure.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
		foreach (var info in props)
		{
			object o = info.GetValue(objToConfigure, null);
			if (o == null) continue;
			if (info.PropertyType.IsGenericCollection())
			{
				ICollection c = o as ICollection;
				if (c != null)
					foreach (var obj in c)
						container.Release(obj);
			}
			else if ((info.PropertyType.IsInterface) || (info.PropertyType.IsClass))
			{
				container.Release(o);
			}
		}
	}
}

I am using the newly released Castle Windsor 2.5 so these methods can also take advantage of the new CollectionResolver (if you configure the container to use it).

However carefully consider this advice: if you want to use this method, you should be aware of what you are doing and you should also know all your object structures, hierarchies and dependencies! Introducing unwanted side effects can be extremely easy: just think if one of your subcomponents have a dependency to the object you are configuring...who is responsible for resolving those dependencies? The container itself can’t, because it does not know the object, or in the worst case it will create a duplicate of the object and inject it in the ‘child’ elements.



Castle windsor

1 comments

Related Post

  1. #1 da Robert - Sunday September 2010 alle 11:53

    Hi, Guardian!
    Nice post and thanks for highlighting CollectionResolver.
    I have another approach to this problem. It might be interesting to you, here is the link: http://robbbloggg.blogspot.com/2010/09/windsor-castle-buildup.html

    Regards, Robert.

All fields are required and you must provide valid data in order to be able to comment on this post.


(will not be published)
(es: http://www.mysite.com)


  1. #1 da http://blog.cwa.me.uk/2010/09/02/the-morning-brew-677/

    The Morning Brew - Chris Alcock &raquo; The Morning Brew #677