根据环境改变接口的实现

本文关键字:实现 接口 改变 环境 | 更新日期: 2023-09-27 17:53:26

我有一个使用接口IBackend与后端通信的应用程序。在生产环境中,我希望使用类ProdBackend : IBackend作为接口的实现。在测试环境中,我希望使用TestBackend : IBackend

应用程序被打包到一个zip文件中,该文件必须独立于它是部署在prod环境还是测试环境中。

如何使应用程序根据其部署的环境使用不同的IBackend实现?

我可以通过简单地在两个环境中安装不同的.dll并命名相同的类来做到这一点吗?

UPDATE 11:12 - 15/1:打包的应用程序不允许包含prod实现,即ProdBackend : IBackend。因此,应用程序在编译时不知道ProdBackend : IBackend

根据环境改变接口的实现

根据您的设置,有许多方法可以做到这一点。我能想到这些:

  1. 机器名:如果您知道测试服务器的服务器名(或约定),您可以根据Envirnoment.MachineName新建依赖项。
  2. Plugin:如果您使用插件模型(通过构建包含ProdBackend的程序集和包含TestBackend的程序集),您可以在部署应用程序时做出决定。你可以有一个插件目录,你的IOC容器将使用它来连接依赖项(或其他方式)。
  3. Configuration:您可以使用配置文件中的值来确定环境,然后使用该信息在两个实现之间进行选择。然后,在部署到prod环境时,可以相应地调整配置文件(app.config)。

为相同接口的不同实现提供不同的DLL将工作得很好。

一个更优雅的解决方案是这样做,但要添加一个提供所需实现的服务定位器。然后,您可以配置Service Locator以返回基于您所运行的平台的实现。

有很多服务定位器,但有一个简单的可以在Mono支持的所有平台上运行的是TinyIOC

测试环境的全部意义在于允许您尽可能合理地确定,当您将某些内容部署到生产环境时,它将正常工作。如果您有一组代码在测试中执行,而另一组代码在部署到生产环境时执行,那么您是如何实现这个目标的?

本质上,从代码的角度来看,测试和生产之间的区别应该只是配置(不同的数据库连接,可能在测试上更详细的日志记录,等等)。否则,从本质上讲,您是在将未经测试的代码部署到生产环境中,在我看来,这是在为可能的灾难播下种子。

有一个概念:上下文绑定——几乎所有依赖注入容器都实现了这个概念。在实践中,这意味着您可以在绑定中添加条件。下面是使用ninject

的例子

定义"生产"环境条件

例如Environment.MachineName,或任何其他适合您的:

private static readonly Func<bool> IsCurrentEnvironmentProduction = 
   () => Environment.MachineName == "Production.Server";

为不同的环境定义绑定

public static IKernel InitializeKernel() 
{ 
    var kernel = new StandardKernel();
    // binding for production
    kernel
        .Bind<IBackend>()
        .To<ProdBackend>()
        .When(request => IsCurrentEnvironmentProduction());
    // binding for test environment
    kernel
        .Bind<IBackend>()
        .To<TestBackend>()
        .When(request => !IsCurrentEnvironmentProduction());
    return kernel; 
}

解析实例依赖于环境

DI容器会为你做一切

var backend = kernel.Get<IBackend>();

完整样本在这里

关于Mono的说明

根据Ninject下载,Mono有一个发布版本,但是你也可以在其他DI容器中实现相同的功能