Search code examples
c#inversion-of-controlsimple-injector

Simple injector how to register /resolve collection of singletons against same interface


So I have this class that I would like to register multiple singletons off, where I would like to distinguish between them (after resolving from container) using the "ExchangeName" property

public interface IGlobalExchangeRateLimitProvider
{
    void DoSomethingWithDb();
    string ExchangeName { get; }
}

public class GlobalExchangeRateLimitProvider : IGlobalExchangeRateLimitProvider
{
    private object _syncLock = new object();

    public GlobalExchangeRateLimitProvider(string exchangeName)
    {
        ExchangeName = exchangeName;
    }

    public void DoSomethingWithDb()
    {
        lock (_syncLock)
        {

        }
    }

    public string ExchangeName { get; }
}

And this is what I have in simple injector to register a collection

var container = new Container();
container.Collection.Register(new[]
{
    Lifestyle.Singleton.CreateRegistration<IGlobalExchangeRateLimitProvider>(
        () => new GlobalExchangeRateLimitProvider("A"), container),
    Lifestyle.Singleton.CreateRegistration<IGlobalExchangeRateLimitProvider>(
        () => new GlobalExchangeRateLimitProvider("B"), container)
});
container.Verify();

This all looks cool

But when I try and resolve the collection like this

var globalExchangeRateLimitProviders =
    container.GetAllInstances<IGlobalExchangeRateLimitProvider>();

I get the following error

enter image description here

No registration for type IEnumerable<IEnumerable<IGlobalExchangeRateLimitProvider>> could be found.

I mean I can guess why this is, it is due to the fact that what I currently have registered is a IEnumerable<Registration> not IEnumerable<IGlobalExchangeRateLimitProvider>

But I am just not sure how to wire up SimpleInjector to give me what I want here. What do I need to do in order to register the above an get an IEnumerable<IGlobalExchangeRateLimitProvider> out of the container?

How can I achieve this using SimpleInjector?


Solution

  • You are calling the wrong Register<T> overload. You are actually calling Register<T>(params T[] singletons), instead of calling Register<T>(IEnumerable<Registration> registrations). This causes the registrations to be made as a collection of Registration instances, instead of a collection of IGlobalExchangeRateLimitProvider instances, as can be seen when hovering over the verified container:

    Simple Injector's debug view showing the root registrations

    Instead, include the type of the collection when calling Collection.Register

    var container = new Container();
    container.Collection.Register<IGlobalExchangeRateLimitProvider>(new[]
        {
            Lifestyle.Singleton.CreateRegistration<IGlobalExchangeRateLimitProvider>(
                () => new GlobalExchangeRateLimitProvider("A"), container),
            Lifestyle.Singleton.CreateRegistration<IGlobalExchangeRateLimitProvider>(
                () => new GlobalExchangeRateLimitProvider("B"), container)
        });
    container.Verify();