I'm using the Simple Injector IoC framework, and I would like to be able to change the dependency registration at run time. For example, I have two implementations, A
and B
, of interface I
. Implementation A
is registered at app start, but depending on some flag which can change during runtime, I would like to switch the implementation. We are currently doing this the OnActionExecuting
event of our BaseController
, which all of our controllers inherit from. Here is the sample code of what I am trying to do.
protected override void OnActionExecuting(
ActionExecutingContext filterContext)
{
if (IsRuntimeFlag)
{
// check current implementation type and
// change implementation to A
}
else
{
// check current implementation type and
// change implementation to B
}
base.OnActionExecuting(filterContext);
}
Thanks in advance for your help.
In case IsRuntimeFlag
is a configuration value (thus cannot change during the lifetime of the application), you can make the registration as follows:
if (IsRuntimeFlag)
{
container.Register<I, A>();
}
else
{
container.Register<I, B>();
}
or equally:
container.Register(typeof(I), IsRuntimeFlag ? typeof(A) : typeof(B));
In case the value can change during the lifetime of the application a proxy or composite that deals with dispatching to the right instance is the right solution:
public sealed class RuntimeFlagIComposite : I
{
private readonly A a;
private readonly B b;
public RuntimeFlagIComposite(A a, B b) {
this.a = a;
this.b = b;
}
void I.Method() => this.Instance.Method();
private I Instance => IsRuntimeFlag ? this.a : this.b;
}
Because the composite directly depends on A
and B
, you can simply register it as follows:
container.Register<I, RuntimeFlagIComposite>();
When A
or B
have a different lifetime than transient (a new instance for each request), you should also register them. For instance:
container.Register<A>(Lifestyle.Singleton);
container.Register<B>(Lifestyle.Scoped);
You can also let your composite depend on the I
abstraction itself instead of the concrete A
and B
implementations:
public class RuntimeFlagIComposite : I
{
private I a;
private I b;
public RuntimeFlagIComposite(I a, I b)
{
this.a = a;
this.b = b;
}
}
Depending on the I
abstraction makes this class more flexible and more testable. It does mean however, that you need to register it a little bit different:
container.Register<I, RuntimeFlagIComposite>();
container.RegisterConditional<I, A>(c => c.Consumer.Target.Name == "a");
container.RegisterConditional<I, B>(c => c.Consumer.Target.Name == "b");