简单的注入器在运行时更改注册

时间:2015-09-24 15:01:21

标签: c# asp.net-web-api dependency-injection simple-injector

我使用Simple Injector和ASP.NET Web API项目,我想对一个接口使用不同的实现,具体取决于所使用的REST端点的版本。例如,如果使用端点的v1,则IPaymentData应使用名为PaymentData的类进行实例化,但如果使用v2 IPaymentData应由名为{{1}的类实现}。结果证明这是有问题的!

我不想使用类似Simple Injector文档的一部分的复合类,因为这意味着我的代码需要注意并考虑我使用的注入框架(坏)

我注意到在最新版本(3.0)中,名为"Context based injection"的内容是一项功能。使用PaymentDataNew函数,每次解析类型时都应该可以运行委托。

container.RegisterConditional

这似乎不起作用,因为即使生命周期是作用域,默认生活方式是container.RegisterConditional(typeof(IPaymentData), c => ((HttpContext.Current.Items["version"] as string ?? "1") == "2") ? typeof(PaymentDataNew) : typeof(PaymentData), Lifestyle.Scoped, c => true); ,根据版本返回实现的委托只调用第一个请求进来。后续请求跳过此(他们似乎使用缓存实现)。

我有什么遗失的东西吗?如何在每次请求进入时确保调用委托?

1 个答案:

答案 0 :(得分:6)

  

因为这意味着我的代码需要注意并考虑我正在使用的注入框架

不完全是。复合模式是众所周知且常用的模式,因此在代码中定义它不会使您的代码依赖于DI库。如果您不想在应用程序代码中定义组合,则可以始终在Composition Root中指定组合。 Composition Root已经非常依赖于DI库,所以任何特定于库的东西都应放在那里。

  

使用container.RegisterConditional函数,每次解析类型时都应该可以运行委托。

Simple Injector v3的RegisterConditional方法允许根据静态信息有条件地应用注册。这意味着所提供的谓词仅被称为有限的时间量(通常每个消耗组件一次)。方法(IntelliSense / XML)文档states

  

谓词只会被评估有限次数;谓词不适合根据运行时条件做出决定。

每次解决时都会调用 。原因有两个:

  1. 这可以优化性能,因为在谓词中做出的决定可以刻录到已编译的表达式中,但更重要的是,
  2. 这可以防止您在构建对象图时做出运行时决策。
  3. 对象图的形状不应取决于运行时参数(例如version中的HttpContext)。这样做会使对象图变得复杂,并且使对象图的verifydiagnose变得非常困难。

    我建议的解决方案是为IPaymentData实现一个允许在运行时进行切换的代理实现。这是不是 Simple Injector特定的实现;你应该努力拥有简单,静态和可验证的对象图,而不管你使用的DI库。

    这就是代理的样子:

    public sealed class HttpRequestVersionSelectorPaymentData : IPaymentData
    {
        private readonly PaymentData paymentOld;
        private readonly PaymentDataNew paymentNew;
        public VersionSelectorPaymentData(PaymentData old, PaymentDataNew paymentNew) { ... }
    
        private bool New => HttpContext.Current.Items["version"] as string ?? "1") == "2";
        private IPaymentData PaymentData => this.New ? paymentNew : paymentOld;
    
        // IPaymentData method(s)
        public Payment GetData(int id) => this.PaymentData.GetData(id);
    }
    

    虽然绝对有可能在构建对象图期间做出运行时决策(通过注册委托),但我强烈建议不要这样做,原因如上所述。