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

Tor*_*rfi 4 c# dependency-injection simple-injector asp.net-web-api

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

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

我在最新版本(3.0)中注意到一种称为"基于上下文的注入"的功能.使用该container.RegisterConditional函数,每次解析类型时都应该可以运行委托.

container.RegisterConditional(typeof(IPaymentData),
    c => ((HttpContext.Current.Items["version"] as string ?? "1") == "2") 
        ? typeof(PaymentDataNew) 
        : typeof(PaymentData),
    Lifestyle.Scoped,
    c => true);
Run Code Online (Sandbox Code Playgroud)

但是,这似乎不起作用,因为即使生命周期是作用域,并且默认生活方式是WebApiRequestLifestyle根据版本返回实现的委托只调用第一个请求.后续请求跳过此(它们似乎使用缓存实现).

有什么我想念的吗?如何在每次请求进入时确保调用委托?

Ste*_*ven 6

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

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

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

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

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

每次解决时都不会调用它.原因有两方面:

  1. 这样可以优化性能,因为谓词中的决策可以烧写到编译表达式中,但更重要的是,
  2. 这可以防止您在构建对象图时做出运行时决策.

对象图的形状不应该依赖于运行时参数(例如version你的HttpContext).这样做会使对象图变得复杂,并且很难验证诊断对象图的正确性.

我建议的解决方案是实现一个代理实现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);
}
Run Code Online (Sandbox Code Playgroud)

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