Is it possible in any way to deduplicate registration in unity?

Oct 4, 2012 at 10:59 AM
Edited Oct 4, 2012 at 11:01 AM

Consider interfaces:

public interface IOne{}

public interface ITwo{}

public interface IBoth : IOne, ITwo{}

And class

public class Both : IBoth{}

When I need to resolve base interfaces I need to register both interfaces in container

<register type="IOne" MapTo="Both"/>
<register type="ITwo" MapTo="Both"/>

The question is - can I deduplicate the registration in a way like this:

<register type="IBoth" MapTo="Both"/>

But resolve it in different places from different interfaces:

var o = containet.Resolve<IOne>();

var t = containet.Resolve<ITwo>();

Can I do such a trick in any other way since this scenario is not working?...

Oct 5, 2012 at 2:13 AM

As you noticed, there is no out of the box support for automatically registering interfaces.  The good news is that you can use a "trick" to register all of the interfaces.  In Unity a "trick" is usually a container extension.  So in this case the container extension would look like this:

public class UnityMultipleInterfaceRegisterer : UnityContainerExtension
    private static readonly object[] EmptyObjectArray = new object[0];
    private static readonly Type[] EmptyTypeArray = new Type[0];

    // Keep constructors for LifetimeManagers
    private static readonly ConcurrentDictionary<Type, ConstructorInfo> lifetimeManagerConstructors 
        = new ConcurrentDictionary<Type, ConstructorInfo>();

    protected override void Initialize()
        base.Context.Registering += new EventHandler<RegisterEventArgs>(this.OnRegister);

    private void OnRegister(object sender, RegisterEventArgs e)
        IUnityContainer container = sender as IUnityContainer;

        if (e != null && e.TypeFrom != null && e.TypeFrom.IsInterface)
            foreach (var interfaceType in e.TypeFrom.GetInterfaces())
                if (interfaceType.IsAssignableFrom(e.TypeTo))
                    ConstructorInfo constructor = lifetimeManagerConstructors.GetOrAdd(
                        e.LifetimeManager.GetType(), (t) => e.LifetimeManager.GetType().GetConstructor(EmptyTypeArray));

                    // Create new LifetimeManager for this registration since we can't reuse it
                    LifetimeManager lifetimeManager = (LifetimeManager)constructor.Invoke(EmptyObjectArray);

                    container.RegisterType(interfaceType, e.TypeTo, e.Name, lifetimeManager);

So in this extension if the registered from type (e.g. IBoth) is an interface then get all of the interfaces that the from interface implemements (e.g. IOne, ITwo) and register those to map to the same concrete type (e.g. Both).

Then you can just have the config look like this:

<?xml version="1.0" encoding="utf-8" ?>
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/>

  <unity xmlns="">

      <extension type="UnityMultipleInterfaceRegisterer"></extension>
      <register type="IBoth" mapTo="Both"/>



But in the code you can now do this:

var container = new UnityContainer();

var both = container.Resolve<IBoth>();
var one = container.Resolve<IOne>();
var two = container.Resolve<ITwo>();

Randy Levy
Enterprise Library support engineer