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:
I1
.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:
RegisterSingle
.container.Options.AllowOverridingRegistrations = true
before calling RegisterSingle
(disabling it afterwards would be safest).