3

我们有一个非常庞大复杂的企业应用程序,在2005年IOC容器在.NET中广泛使用之前,它始于2005年。我们希望改造IOC容器,作为我们迁移到基于RabbitMQ(和easynetq)的完整事件驱动架构的一部分。作为一项业务,我们同意这将给我们带来比竞争对手更多的商业优势。Retro将IOC容器安装到Brownfield Enterprise .net应用程序

我觉得给一些序言作为实施战略的关键是它很重要:

  • 150万条+使用.NET 4,在600多个项目中,30000+类的C#线,40000+单元测试部署在过50个不同的应用程序端点(命令行exe,Windows服务,Web服务等)。
  • 该应用程序的简单CRUD的数量少于10%。大多数应用程序是复杂的事务处理,其中一个输入值可以轻松地通过20到30个依赖关系,这可能与2或3个其他子系统和/或模块对话。
  • 我们每个月都会向所有具有各种不同配置的客户发布一次重要的新版本,应用程序非常稳定,但我们仍在积极进行创新。我们需要迁移12至36个月。
  • 可扩展性和性能对我们非常重要。我们已经测试了每秒超过1500次的事务和80ms的响应时间。每毫秒都很重要。
  • 非常稳定和相当一致的架构,在控制庄园不断发展 - 开发是相当无痛的。

目前所有的依赖注入的构造基础,手卷:

public sealed class TestCommandHandler 
{ 
     private readonly IUnitOfWork _unitOfWork; 
     private readonly ITestCommandValidator _testCommandValidator; 

     public TestCommandHandler(IUnitOfWork unitOfWork) 
     { 
      this._unitOfWork = unitOfWork; 
      this._testCommandValidator = new ITestCommandValidator(unitOfWork); 
     } 

     public TestCommandHandler(IUnitOfWork unitOfWork, IValidator testCommandValidator) 
     { 
      this._unitOfWork = unitOfWork; 
      this._testCommandValidator = testCommandValidator; 
     } 
    } 

工作单位包含访问资源库,可以很容易地嘲笑:

public class UnitOfWork : IUnitOfWork, IDisposable 
{ 
     private IAccountRepository _accountRepository; 

     public IAccountRepository Account 
     { 
      get 
      { 
       if(this._accountRepository == null) 
       { 
        this._accountRepository = new AccountRepository(this); 
       } 
       return this._accountRepository; 
      } 
      set 
      { 
       this._accountRepository = value; 
      } 
     } 
     //Begin Tx, Commit Tx etc 
} 

目前所有的测试依赖项都是以调试模式进行条件编译的。发布代码在创建具体依赖关系的地方使用非条件代码。 最大的对象依赖是UnitOfWork,它通常在每个业务事务周围创建并传递到堆栈。例如,

using(var unitOfWork = new UnitOfWork()) 
{ 
} 

这通常包装在另一个也支持IDisposable的类中。我们还计划将AccountID传入UnitOfWork,以便我们可以轻松地使用mod函数针对不同的数据库向前推进。

为了转移到依赖框架,感觉我们需要首先将UnitOfWork排序,但我们需要一个婴儿步骤。我非常希望能够通过如此庞大的应用程序来实现这一目标。我们计划在圣诞节期间进行第一阶段,在那里我们有一个很好的冻结,并将所有绝望的分支合并为一个主线分支,以做出重大改变。

我们打开要使用的依赖注入框架。我们已经和StructureMap玩过一段时间了。我们看到Ninject在Nuget上的下载数据很高,但在性能上看它的分数很差。我们并不需要进一步的迁移过程到另一个依赖注入框架。所以我们愿意提供建议。这不是一场最好的宗教战争,更重要的是我们有一些东西可以迁徙。最重要的要求是流畅地配置,以避免配置地狱。

其他关切,我们必须在StructureMap方面,就是我们如何申报登记。我们是否宣布每个程序集的注册表?任何推荐的文件夹命名标准,大型应用程序中的类名称?我粗略猜测将会有大约1000个注册管理机构。此外,关于扫描如此庞大的代码库策略的想法?我们应该担心吗?

感谢准备这么远,但背景是重要的,因为它不是一个10分钟的工作。

休伯特

+0

我也用ninject相当长一段时间,喜欢它的界面。既然你需要表现,我会考虑Autofac。它的功能与Ninject类似,但似乎表现更好。另见:http://www.palmmedia.de/blog/2011/8/30/ioc-container-benchmark-performance-comparison – BatteryBackupUnit 2014-10-31 13:52:31

回答

2

张贴这作为一个答案,但没有正确的asnwer您的问题,只是为了克服评论限制。

你为了实现国际奥委会在你的方案有很多优点:

  1. 你的类已经分离和构造器注入的准备;
  2. 使用条件标志拆分您的依赖关系。

所以,我只想根据您目前的情况指出几点建议。

  • 如果性能至关重要,请小心使用Ninject。作为一名沉重的Ninject用户,我发现它对Fluent配置,模块和上下文绑定非常灵活和强大。但是,所有这些能力都有一个价格,并且与其他IoC容器相比,每个激活请求的性能会更差。不管选择的框架

  • 既然你已经开始引入这些变化,你不希望被束缚的容器。确保你抽象它,然后你可以开启另一个。

  • 您已经具有配置分割你的“模块”。确保在插入容器配置代码时将它们收集在模块中。不要为所有配置在一个地方的模块留下所有依赖关系。 Ninject支持模块,但使用任何容器很容易实现,特别是如果你抽象它们。不要对虚拟/实际实现使用相同的模块名称,而是根据您的配置加载一个或另一个模块。

  • 根据“自动注册”或“约定”,您应该是非常严格并小心标准或否则很容易搞砸了。我强烈建议不要使用积极的前期自动注册查询,并将它们保持在最小和非常简单的情况下,例如“IAccountRepository” - >“AccountRepository”或“AccountRepositoryImpl”。即使是这些,你也可以通过模块来分割约定,以便可以将它们覆盖用于测试目的。

  • 您的发布周期内做小的变化一般,不做分支修改,直到你融入他们保留他们那里。就像你说的,宝贝步骤。你已经有依赖注入,所以这将是无痛的。强化团队内的这一策略以使用容器,并在功能实施或重做时做小的更改。

这就是我的2美分,希望它有帮助。

+0

我同意抽象依赖框架是一个好主意。我们抽象了其他所有东西,并且之前已经多次切换技术。团队在这方面非常有经验,每个人都为保持有组织的代码而感到自豪;否则,一大块泥球就会保证。这是我们现在改变的部分原因 – 2014-10-30 16:35:48