Search code examples
c#.netdependency-injectionunity-container

Unity Resolution fails when Singleton is registered with named parameter


I have the following class and interface definitions:

interface IView { ... }

interface IViewA : IView { ... }
interface IViewB : IView { ... }

class ViewA : IViewA { ... }
class ViewB : IViewB { ... }

class Controller
{
     public Controller(IViewA view) { ... }
}

And I register them in the unity container like this:

unityContainer.RegisterSingleton<IViewA, ViewA>("TheTestViewA");
unityContainer.RegisterSingleton<IViewB, ViewB>("TheTestViewB");
unityContainer.RegisterSingleton<Controller>();

However when I then request the instance of the controller, unity throws an exception.

unityContainer.Resolve<Controller>();

Resolution failed with error: No public constructor is available for type IViewA.

It seems that it wants to construct the interface and not the class. I also found out, that when I omit the naming parameter "TheTestViewA" it works fine. However I need that parameter because later on I need to container.ResolveAll<IView>() which only works when the mapping has a name. ( ResolveAll not working )


Solution

  • The exception is confusing, but what happens is that Unity can't find a registration for IView. For it to be able to inject an IView into Controller, it requires a nameless registration for IView, but all it has is a named registration (TheTestViewA).

    Since a registration for IView is missing, Unity assumes IView is a concrete type and tries to instantiate it. But IView has no constructors (because its an interface), hence the exception.

    You can try the following code instead:

    var unityContainer = new UnityContainer();
    
    unityContainer.RegisterSingleton<ViewA>();
    unityContainer.RegisterSingleton<IViewA, ViewA>();
    unityContainer.RegisterSingleton<IViewB, ViewB>();
                
    unityContainer.RegisterFactory<IView>("A", c => c.Resolve<IViewA>(), new SingletonLifetimeManager());
    unityContainer.RegisterFactory<IView>("B", c => c.Resolve<IViewB>(), new SingletonLifetimeManager());
    
    unityContainer.RegisterSingleton<Controller>();