Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to change dependency registration at run time using simple injector?

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.

like image 424
Will Avatar asked Aug 23 '12 02:08

Will


People also ask

Does dependency injection happen at runtime?

Dependency Injection ( DI ) is therefore used to resolve dependencies at runtime rather than at compile time. Objects that have dependencies will not themselves create those dependencies.

What are different ways to inject the dependencies?

There are three types of dependency injection — constructor injection, method injection, and property injection.

How does dependency injection remove dependency?

Dependency injection is a programming technique that makes a class independent of its dependencies. It achieves that by decoupling the usage of an object from its creation. This helps you to follow SOLID's dependency inversion and single responsibility principles.

Is simple injector safe?

Simple Injector is thread-safe and its lock-free design allows it to scale linearly with the number of available processors and threads. You will find the speed of resolving an object graph comparable to hard-wired object instantiation.


1 Answers

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>();

// Register A and B with their required lifestyles
container.Register<A>(Lifestyle.Singleton);
container.Register<B>(Lifestyle.Transient);

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. This can be done using RegisterConditional. Here's an example:

container.Register<I, RuntimeFlagIComposite>();

container.RegisterConditional<I, A>(c => c.Consumer.Target.Name == "a");
container.RegisterConditional<I, B>(c => c.Consumer.Target.Name == "b");
like image 160
Steven Avatar answered Sep 22 '22 01:09

Steven