2012-08-23 45 views
5

我正在使用Simple Injector IoC框架,我希望能够在运行时更改依赖项注册。例如,我有两个实现,AB,接口为I。实现A是在应用程序启动时注册的,但根据某些可在运行时更改的标志,我希望切换实现。我们目前正在执行我们的BaseControllerOnActionExecuting事件,这是我们所有控制器继承的事件。这是我正在尝试做的示例代码。如何使用简单注入器在运行时更改依赖注册?

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

在此先感谢您的帮助。

+1

我建议结合工厂和战略模式,而不是使用DI容器为此。尽早使用Container来解析对象图。参见[Composition Root](http://blog.ploeh.dk/2011/07/28/CompositionRoot.aspx)。 – TrueWill

+0

您是否需要手动执行此操作?使用IOC容器框架怎么样? –

回答

9

万一IsRuntimeFlag是一个配置值(因此该应用程序的生命周期内不能改变),就可以使登记如下:

if (IsRuntimeFlag) 
{ 
    container.Register<I, A>(); 
} 
else 
{ 
    container.Register<I, B>(); 
} 

或同等:

container.Register(typeof(I), IsRuntimeFlag ? typeof(A) : typeof(B)); 

万一该值可以在应用程序的生命周期期间更改代理或composite,处理调度到正确的实例是正确的解决方案:

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; 
} 

由于复合直接取决于AB,可以简单地如下进行注册:

container.Register<I, RuntimeFlagIComposite>(); 

AB具有不同的寿命比瞬态(每个请求一个新的实例),则也应该注册它们。例如:

container.Register<A>(Lifestyle.Singleton); 
container.Register<B>(Lifestyle.Scoped); 

你也可以让你的组合取决于I抽象本身,而不是具体的AB实现:

public class RuntimeFlagIComposite : I 
{ 
    private I a; 
    private I b; 

    public RuntimeFlagIComposite(I a, I b) 
    { 
     this.a = a; 
     this.b = b; 
    } 
} 

根据I抽象使得这个类更灵活,更测试。然而,它的意思是,你需要注册一点点不同:

container.Register<I, RuntimeFlagIComposite>(); 

container.RegisterConditional<I, A>(c => c.Consumer.Target.Name == "a"); 
container.RegisterConditional<I, B>(c => c.Consumer.Target.Name == "b"); 
+0

谢谢您的回答,但是,此标志在容器注册时是未知的,并且可以在应用程序的整个生命周期中进行更改。我想我可以设置一个全局标志并在应用程序的后期更改,但我认为这不是一个干净的方法。仔细一看,我确实认为复合模式可能适用于这种情况。再次感谢你的帮助。 – Will

+0

嗨史蒂文, 只是想知道如果你有任何其他的想法。试图实现这一点,我意识到该标志还取决于Web应用程序层中的东西,特别是cookie值,而不是服务层,这是复合材料所在的位置。因此,该组合将无法访问该标志。再次提前感谢。 – Will

+1

我想你回答了你自己的问题。如果组合将取决于UI特定的事情,它应该在UI层中定义。由于界面是在较低层定义的,因此在您的UI层中定义界面绝对没问题(或者您甚至可以将它作为您的组合根的一部分)。 – Steven