0

I'm trying to register by convention multiple implementation of single interface and later use all those interfaces as dependency in other classes. Unfortunatelly, I'm having some problems trying to do so.

I want to register multiple implementation, so I added WithName.TypeName druing registration but this seems to be causing problems. Without it, I can't register multiple implementations for single interface.

Below is simple example which is not working. Unity is throwing exception and I don't know why.

Unity.ResolutionFailedException: 'Resolution failed with error: No public constructor is available for type KYPClient.IConf.

namespace KYPClient
{
public interface IConf
{
    string conf();
}

public class Conf : IConf
{
    public string conf()
    {
        return "conf";
    }
}

public interface ILoader
{
    string load();
}

public class Load_1 : ILoader
{
    public string load()
    {
        return "load-1";
    }
}

public class Load_2 : ILoader
{
    public string load()
    {
        return "load-2";
    }
}

public class MainCls
{
    private IConf _conf;
    private IEnumerable<ILoader> _loaders;

    public MainCls(IConf conf, IEnumerable<ILoader> loaders)
    {
        _conf = conf;
        _loaders = loaders;
    }

    public void Run()
    {
        System.Console.WriteLine(_conf.conf());
        foreach (var l in _loaders)
        {
            Console.WriteLine(l.load());
        }
    }
}


internal static class Client
{
    private static void Main()
    {   
        using var container = new UnityContainer();

        container.RegisterTypes(
            AllClasses.FromAssemblies(typeof(MainCls).Assembly),
            WithMappings.FromAllInterfaces,
            WithName.TypeName,
        WithLifetime.ContainerControlled);

        var main = container.Resolve<MainCls>();

        main.Run();
    }
}

}

sop3k
  • 101
  • 2
  • 8
  • What do you mean? Registration code is there - RegisterTypes. There is also constructor for MainCls which is only ony required here. – sop3k Dec 17 '19 at 17:53

1 Answers1

0

The issue is you're using the WithName.TypeName option. This means that each type from the assembly is done as a named registration in the container. This is a good thing in your case because you are registering multiple ILoader instances, so the container has to be able to differentiate them. However, it also means that when it's being resolved, you have to pass the name in order for the container to find it.

In other words, when the container sees the constructor public MainCls(IConf conf, IEnumerable<ILoader> loaders) it interprets that as "inject the IConf instance with the default name" which doesn't exist in your container. Your IConf is registered with the name "Conf" (or possibly "KYPClient.Conf", I'm not sure, as I've never used the RegisterTypes method).

Thus, you have to explicitly name it in your constructor. Also, per How to configure Unity to inject an array for IEnumerable you need an array to get all the registered ILoader types.

public MainCls([Dependency("Conf")] IConf conf, ILoader[] loaders)

Of course, there are some drawbacks to using named dependencies (such as, what happens if you refactor and rename your class). Take a look at the second answer to With Unity how do I inject a named dependency into a constructor? for a strategy around that using a factory pattern.

howcheng
  • 2,211
  • 2
  • 17
  • 24