Suggestion: IUnityContainer visibility from TypeResolvingConfigurationElement.

Mar 29, 2008 at 4:12 AM
Edited Mar 29, 2008 at 4:13 AM
There have been a few times while constructing my ConfigurationElements (TypeInjection and now InjectionParameterValueElement) that I would like to have access to the IUnityContainer that the element is configuring. I've extended TypeInjectionElement and have done the following:

class TypeInjectionElement : Microsoft.Practices.Unity.Configuration.TypeInjectionElement
{
	public override void Configure(IUnityContainer container)
	{
		foreach ( InjectionMemberElement element in InjectionMembers )
		{
			IContainerConfigurationCommand command = element as IContainerConfigurationCommand;
			if ( command != null )
			{
				command.Configure( container );
			}
		}
		base.Configure(container);
	}
}

However, that only does the first level of elements. I would like to suggest implementing something like how the TypeResolver is assigned to each child element throughout the configuration hierarchy, only for the current IUnityContainer instead. :)
Mar 29, 2008 at 5:04 AM
You have no idea how painful it was to get the typeresolver passed down to the right spots. It still doesn't work quite right, either; for example, you can't use a type alias for the element types because they're not available yet (they don't get set until after serialization is complete). As such, I don't want to go through that again for everything else that could or should flow down the configuration tree. ;-) I've got some ideas on how stuff might be done better, but they'll unfortunately have to wait until after we get 1.0 out.

I've come to the conclusion that System.Configuration really isn't very general, and the way we're using it (with extensible elements) breaks the model it was designed for. Unfortunately we need that extensibility, so a future task is to figure out how to get it (System.Configuration) to shut the heck up and get out of our way.

Mar 29, 2008 at 12:15 PM
In order to solve a similar problem in the past, I've pushed the instance of what was needed further down on TLS just before deserialization. It's been working like a charm so far.

In looks something like:

using (ThreadLocalStorage.Push(container))
{
  section = (UnityConfiguratioSection)ConfigurationManager.GetSection("unity");
}

and then in my ConfigurationElement:

  container = ThreadLocalStorage.Peek<IUnityContainer>();
  container.Resolve<IFoo>();
Mar 29, 2008 at 2:08 PM
Francois, your new name is Magic Man! I will incorporate that into my creation method.

Chris, despite all the ConfigurationAPI hassles (and I'm beginning to understand just what you guys were fuming over), I still think your implementation of how you guys work around its limitations is really well done, but that's just me. I mean, this typeconfiguration stuff is really awesome. I've been able to plug-in and extend with my own elements with no problems outside what I've pointed out here (which has now been solved). I think you guys have a lot to be proud of for a 1.0 release!
Mar 29, 2008 at 2:18 PM


MichaelDBang wrote:
Francois, your new name is Magic Man! I will incorporate that into my creation method.


I spoke too soon. It appears I am short of a very handy helper class, ahem... :)
Mar 30, 2008 at 2:38 PM
eh eh :)

I don't have access to a compiler right now so let's assume it's pseudo code:

public class ThreadLocalStorage
{
  [ThreadStatic] private Dictionary<Type, Stack<object>> items = new ...
 
  public static IDisposable Push<T>(T item)
  {
    Stack<object> stack = GetStack<T>();
    stack.Push(item);
 
    return new DisposableAction { Action = () => stack.Pop() };
  }
 
  public static T Peek<T>()
  {
    return (T)GetStack<T>().Peek();
  }
 
  private Stack<object> GetStack<T>()
  {
    Stack<object> stack;
    if (!items.TryGetValue(typeof(T), out stack))
    {
        stack = new Stack<object>();
        items.Add(typeof(T), stack);
    }
 
    return stack;
  }
}
public class DisposableAction : IDisposable
{
  public Action Action { get; set; }
 
  public void Dispose() { Action(); }
}