将我的MVC提升到新的水平:DI和工作单元

时间:2009-09-26 02:04:43

标签: asp.net-mvc unity-container ioc-container

我已经看过像Nerddinner和ContactManager这样的简单应用程序以及像Kigg这样的更复杂的应用程序。我理解更简单的那些,现在我想了解更复杂的那些。

通常,较简单的应用程序在LINQtoSQL或Entity Framework之上具有存储库类和接口(尽可能松散耦合)。从控制器调用存储库以执行必要的数据操作。

当我检查更复杂的应用程序(如Kigg或Oxite)时,我看到的一个常见模式是引入(我只是在这里略有表面,但我必须从某处开始):

  • IOC DI(在Kigg案例中为Unity)
  • 网络请求终身经理
  • 工作单元

以下是我的问题:

据我所知,为了真正拥有一个松散耦合的应用程序,你必须使用像Unity这样的东西。但是,当你将Unity引入混合时,你也必须引入一个Web Request Lifetime Manager。这是为什么?为什么像Nerddinner这样的示例应用程序没有Web请求终身管理器?它到底是做什么用的?这是Unity特定的事情吗?

我注意到的第二种模式是引入工作单元。同样,同样的问题:为什么Nerddinner或ContactManager不使用工作单位?相反,这些应用程序使用Linq2Sql或Entity Framework之上的存储库类来执行数据操作。没有任何工作单位的迹象。究竟是什么以及为什么要使用它?

由于

以下是DinnersController级别Nerddiner的DI示例:

    public DinnersController()
        : this(new DinnerRepository()) {
    }

    public DinnersController(IDinnerRepository repository) {
        dinnerRepository = repository;
    }

所以我正确地假设因为第一个构造函数控制器“拥有”DinnerRepository,因此它将依赖于控制器的生命周期,因为它在那里被声明了吗?

2 个答案:

答案 0 :(得分:3)

直接使用Linq-to-SQL,您的控制器拥有对数据上下文的引用。它通常是控制器内部的私有引用,因此作为其构造的一部分创建。终身管理没有必要,因为它在一个地方。

但是,当您使用IoC容器时,您的数据存储库将在控制器外部创建。由于为您创建它的IoC容器不知道您将如何以及多长时间使用创建的对象,因此引入了生命周期策略。

例如,数据上下文(存储库)通常在Web请求开始时创建,并在最后销毁。但是,对于使用外部Web服务的组件或某些静态映射器(例如记录器),不需要每次都创建它们。所以你可能想说创造一次(即单身生活方式)。

所有这一切都发生在因为IoC容器(如Unity)旨在处理许多情况,并且他们不知道您的具体需求。例如,某些应用程序使用“对话”事务,其中NHibernate(或实体框架可能)可能在多个页面/ Web请求期间持续。 IoC容器允许您调整对象的生命周期以满足您的需求。但正如所说,这是有代价的 - 因为没有单一的预定义策略,你必须自己选择一个。

为什么NerdDinner和其他应用程序不使用更高级的技术仅仅是因为它们旨在演示MVC功能,而不是其他一些库的高级用法。我记得有一篇文章是为了演示一个IoC容器的高级功能 - 本文打破了一些经过批准的设计模式,比如关注点分离 - 但这并不重要,因为设计模式不是文章的目标。与简单的MVC演示应用程序相同 - 他们不希望MVC新手在IoC迷宫中丢失。

我不建议将Oxite视为设计参考示例: http://codebetter.com/blogs/karlseguin/archive/2008/12/15/oxite-oh-dear-lord-why.aspx http://ayende.com/Blog/archive/2008/12/19/oxite-open-exchangable-informative-troubled-engine.aspx

答案 1 :(得分:0)

我相信大多数(如果不是全部)DI容器都触及生命时代的概念。根据所涉及的场景,您可能希望容器始终返回已注册组件的相同实例,而对于另一个组件,您可能希望它始终返回新实例。大多数容器还允许您指定在特定上下文中,您希望它返回相同的实例等。

我不太了解Unity(到目前为止我已经使用过Windsor和Autofac),但我怀疑Web请求生命周期管理器是生命周期策略的实现,其中容器在生命周期内提供相同的实例。单个Web请求。你会在像温莎这样的容器中找到类似的策略。

最后,我想你指的是工作单位。工作单元本质上是一组您希望作为一个原子业务事务成功或失败的操作。有关更正式的描述,请查看Martin Fowler的definition。这一概念在领域驱动设计的背景下越来越受欢迎。工作单元跟踪您在此类事务中应用的更改,并且在时机成熟时,它会在一个ACID事务中提交这些更改。例如,在NHibernate中,会话支持工作单元的概念,更具体地说是变更跟踪,而在Linq2SQL中它是Context ......