简体   繁体   中英

Multiple RegisterAll registrations using the same set of singletons with SimpleInjector

I'm building a plugin system for an e-commerce project with Simple Injector. I'm using RegisterAll to register all implementation of a IPaymentProvider and of a IResourceRegistrar (and in the fure more).

But this creates a new instance each time. Here is it suggested to use RegisterSingle on each type. But how to achieve this in this case?

private static void RegisterMultipleUnderOneInterface(
    Container container, string name)
{
    IEnumerable<Type> pluginRegistrations =
        from dll in finder.Assemblies
        from type in dll.GetExportedTypes()
        where type.GetInterfaces().Any(i => i.Name == name)
        where !type.IsAbstract
        where !type.IsGenericTypeDefinition
        select type;

    if (pluginRegistrations.Any())
    {
        var @interface =
            pluginRegistrations.ElementAt(0).GetInterfaces()
            .First(i => i.Name == name);

        foreach (Type type in pluginRegistrations)
        {
            // HERE: register the type single somehow. 
        }

        container.RegisterAll(@interface, pluginRegistrations);
    }
} 

container.RegisterSingle(type) does not work, as the types inherent from the same interface ( IPaymentProvider or IResourceRegistrar ). The IPaymentProvider implementing classes have constructors without parameters, the IResourceRegistrar with parameters.

I don't want to do something like this, it rather defeats the purpose of a IoC container

var constructor = type.GetConstructors()[0];

switch (name)
{
    case "IResourceRegistrar":
        container.RegisterSingle(type, () =>
        {
            return constructor.Invoke(new object[
            {
                container.GetInstance<ILanguageService>()});
            });
        break;
    case "IPaymentProvider":
    default:
        container.RegisterSingle(type, () =>
        {
            return constructor.Invoke(new object[] { });
        });
        break;
}

How to register these as singleton without the ugly switch?

Perhaps I misunderstand, but RegisterSingle should work. You should be able to do this:

var types = ...

container.RegisterAll<IInterface>(types);

foreach (var type in types)
{
    container.RegisterSingle(type, type);
}

UPDATE:

So what you are trying to do is to automate the following configuration:

// A, B, C and D implement both I1 and I2.
container.RegisterSingle<A>();
container.RegisterSingle<B>();
container.RegisterSingle<C>();
container.RegisterSingle<D>();

container.RegisterAll<I1>(typeof(A), typeof(B), typeof(C), typeof(D));
container.RegisterAll<I2>(typeof(A), typeof(B), typeof(C), typeof(D));

This would typically be the way to automate this. So do four steps:

  1. Find all types to register.
  2. Register the found types as singleton.
  3. Register the list of types as collection for I1 .
  4. Register the list of types as collection for I2 .

This would look like this:

// using SimpleInjector.Extensions;

Type[] singletons = FindAllTypesToRegister();

foreach (Type type in singletons)
{
    container.RegisterSingle(type, type);
}

container.RegisterAll(typeof(I1), singletons);
container.RegisterAll(typeof(I2), singletons);

However, since you are trying to split this into two steps and create one generic method that can handle each step, you will have to ignore when a concrete singleton type has already been registered. You can either do this by:

  • Ignoring the registration by catching the exception thrown from RegisterSingle .
  • Override an existing registration by setting container.Options.AllowOverridingRegistrations = true before calling RegisterSingle (disabling it afterwards would be safest).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM