如何为特定请求选择一组单独的服务?

How to choose a separate set of services for a particular request?

我正在使用 Simple Injector,它似乎运行良好。有一件事我真的很想做,但我不知道该怎么做,或者如果可能的话,就是根据一些参数更改列表注册服务。

例如:如果我看到一个 URL 参数 &debug=true,那么我想清除已注册服务的列表并用模拟实现替换它们。这将使我的硒测试更容易。

这可能吗?还是完全疯了?

简单注入器开箱即用,更喜欢构建预先完全已知的对象图。缺少允许您根据运行时变量构建不同对象图的内置功能是故意的,因为固定对象图更容易验证,这降低了构建对象图在运行时失败的可能性(在 .Verify() 调用成功)。除了可验证性,它还提高了性能。

但是虽然没有内置任何东西,但仍然有很多方法可以根据运行时条件动态切换服务或整个对象图。我想到的三种可能性是使用 context based injection, runtime decorators 并注册一个简单的委托。

这是一个代表注册的例子:

container.Register<IMailSender>(() => IsDebug(HttpContext.Current)
    ? container.GetInstance<MailSender>()
    : container.GetInstance<MockSender>());

但即使有可能,您也可能需要考虑其他方法。例如,不使用运行时值,而是使用配置值。这在您的情况下似乎非常合理,因为您是否希望能够同时使用您的生产环境进行 Web 测试?对我来说似乎不太可能。特别是因为在同一台服务器上部署第二个 IIS Web 应用程序真的很容易。

因此,您可以为您的 Selenium 框架创建应用程序的特殊部署,并且此部署包含 web.config 和 <add key="Debug" value="True" /> 中的值或类似内容。现在在你的组合根目录中(你 bootstrap 你的容器所在的地方),你可以简单地这样做:

bool debug = bool.Parse(ConfigurationManager.AppSettings["Debug"]);

if (debug) {
    container.Register<IMailSender, MockSender>();
    // more registrations here
} else {
    container.Register<IMailSender, MailSender>();
    // more registrations here
}

这允许在运行时固定对象图,同时仍然能够在部署期间更改内容。