【问题标题】:What good is Unity DI in MVC?MVC 中的 Unity DI 有什么好处?
【发布时间】:2013-04-02 22:43:53
【问题描述】:

我对 Unity 和 IoC 有点陌生,但对 MVC 不熟悉。我一直在阅读和阅读有关将 Unity 与 MVC 结合使用的信息,而我一直看到的唯一真正有用的东西是能够通过控制器获得免费的 DI。

从此出发:

    public HomeController() : this(new UserRepository())
    {
    }

    public HomeController(IUserRepository userRepository)
    {
        this.UserRepository = userRepository;
    }

到这里:

    public HomeController(IUserRepository userRepository)
    {
        this.UserRepository = userRepository;
    }

基本上,允许我删除无参数构造函数。这太棒了,我肯定会实现它,但对于所有关于 IoC 库的炒作来说,这似乎并不是那么好。使用 Unity 作为服务定位器的方式听起来很有吸引力,但许多人会认为这是一种反模式。

所以我的问题是,由于无法找到服务以及使用视图和过滤器的一些 DI 机会,使用 Unity 还能获得什么其他好处吗?我只是想确保我不会错过一些很棒的东西,比如对所有类构造函数的免费 DI 支持。

编辑:

我了解将 Unity DI 与 MVC 控制器结合使用背后的可测试性目的。但我所要做的就是添加一个额外的小构造函数,nix Unity,然后我就可以进行同样的 UnitTest。当替代方案更简单时,注册存储库类型和拥有自定义控制器工厂的巨大好处在哪里?另一种选择是原生 DI。我想我真的想知道 Unity(或任何 IoC 库)除了不好的服务定位之外还有什么好处。免费的 Controller DI 真的是我从 Unity 获得的唯一东西吗?

【问题讨论】:

    标签: c# asp.net-mvc unity-container


    【解决方案1】:

    一个好的 IoC 容器不仅会为您创建具体的类,它还会检查该类型与其他类型之间的耦合。如果有其他依赖项,它会解析它们并创建所有需要的类的实例。

    你可以做一些花哨的事情,比如条件绑定。这是一个使用 Ninject(我首选的 IoC)的示例:

    ninjectKernel.Bind<IValueCalculator>().To<LinqValueCalculator>();
    
    ninjectKernel.Bind<IValueCalculator>().To<IterativeValueCalculator().WhenInjectedInto<LimitShoppingCart>();
    

    ninject 在这里所做的是在注入 LimitShoppingCart 时创建一个 IterativeValueCalculator 实例,并为任何其他注入创建一个 LinqValueCalulator 实例。

    最大的好处是关注点分离(解耦)和可测试性。

    【讨论】:

      【解决方案2】:

      关于为什么服务定位器被认为是坏的(某些人),你可以阅读this blog-post by Mark Seeman

      回答你的问题What is so good in Unity我可以说,除了所有的可测试性,松散耦合和其他大家都在谈论的废话,你可以使用像 Unity's Interception 允许做一些AOP-like 的事情。我在最近的一些项目中使用过它并且非常喜欢它。强烈推荐!

      附言似乎Castle Windsor DI 容器也具有类似的功能(称为拦截器)。其他容器 - 不确定。

      【讨论】:

        【解决方案3】:

        除了测试(这是一个巨大的好处,不应低估),依赖注入允许:

        可维护性:只需一次更改即可更改代码行为的能力。

        如果您决定更改在不依赖注入的情况下跨所有控制器/服务等检索用户的类,您需要更新每个构造函数以及正在创建的任何其他随机新实例,前提是您记得每个实例的位置一个人生活。 DI 允许您更改一个定义,然后在所有实现中使用该定义。

        Scope:只需一行代码,您就可以更改您的实现以创建一个单例,一个仅在每个新的 Web 请求或每个新线程上创建的类

        可读性:使用依赖注入意味着你所有的具体类都定义在一个地方。作为进入项目的开发人员,我可以快速轻松地准确查看哪些具体类映射到哪些接口,并且知道没有隐藏的实现。这意味着我不仅可以更好地阅读代码,而且让我有信心根据代码进行开发

        设计:我相信使用依赖注入有助于创建设计良好的代码。你自动编码到接口,你的代码变得更干净,因为你没有奇怪的代码块来帮助你测试

        别忘了……

        测试:测试是巨大的!依赖注入允许您测试您的代码,而无需专门为测试编写代码。好的,您可以创建一个新的构造函数,但是阻止其他任何人使用该构造函数来实现它不打算用于的目的。如果另一个开发人员在六个月后出现并将生产逻辑添加到您的“测试”构造函数中会怎样。好的,所以你可以将它设为internal,但这仍然可以被生产代码使用。为什么要让他们选择。

        我在 IoC 框架方面的经验主要围绕 Ninject。因此,以上内容基于我对 Ninject 的了解,但是相同的原则在其他框架中应该保持相同。

        【讨论】:

        • 您有没有推荐任何实现 Unity DI 的优秀开源项目?我想看看其他程序员的结构并将其与我的比较,以便可能改进我的解决方案。
        【解决方案4】:

        主要的一点是你在某处有一个映射来指定 IUserRepository 的具体类型。您可能会喜欢这样的原因是,您可以创建一个 UnitTest 来指定 IUserRepository 的模拟版本并执行您的测试,而无需更改控制器中的任何内容。

        【讨论】:

        • 但是@Tim,我所要做的就是添加一个额外的小构造函数,nix Unity,我可以进行同样的 UnitTest。当替代方案更简单时,注册存储库类型和拥有自定义控制器工厂的巨大好处在哪里?
        【解决方案5】:

        主要是可测试性,但我建议看看 Ninject,它与 MVC 配合得很好。要获得 IOC 的全部好处,您应该将其与 Moq 或类似的模拟框架结合起来。

        【讨论】:

          【解决方案6】:

          除了可测试性之外,我认为您还可以添加可扩展性作为优势之一。软件开发的最佳实践之一是“使用抽象,而不是实现”,虽然您可以通过多种方式做到这一点,但 Unity 提供了一种非常可扩展且简单的方法来实现这一点。通过使用它,您将创建抽象来定义您的组件必须遵守的合同。假设您想完全更改您的应用程序当前使用的存储库。使用 DI,您只需“交换”组件,而无需更改应用程序上的一行代码。如果您使用硬引用,您可能需要更改和重新编译您的应用程序,因为它外部有一个组件(在不同的层中)

          因此,恕我直言,最重要的是,使用 DI 可以帮助您在应用程序中拥有可插拔组件并拥有SOLID 应用程序设计

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2017-08-13
            • 2011-10-31
            • 1970-01-01
            • 1970-01-01
            • 2011-09-21
            • 2015-05-14
            • 2015-05-03
            • 1970-01-01
            相关资源
            最近更新 更多