DI&MVC:控制器中的依赖注入有什么意义?

时间:2019-02-27 08:07:52

标签: c# asp.net-mvc design-patterns dependency-injection

短版本

有时我看到一段代码,其中将依赖项注入到控制器的构造函数中,但是它提供了什么好处?

长期版本

让我们假设您正在看到类似以下代码的代码。

//ASP.NET
public class SampleController : Controller 
{
    private IDependency dependency;

    public SampleController(IDependency dependency) 
    {
        this.dependency = dependency;
    }
}

或者,如果您更喜欢PHP,那么让我们看一下下面的

//PHP with Laravel
namespace App\Http\Controllers;

class SampleController extends Controller
{
    private $dependency;

    public function __construct(Dependency $dependency)
    {
        $this->dependency = $dependency;
    }
}

据我所知,依赖注入旨在 使客户端与其依赖项脱钩 ,以便...

  1. 客户端可以在运行时使用不同的依赖项(使用setter方法)
  2. 更新依赖关系类也不太可能迫使您更新客户端

...等等。

但是,控制器没有实例化,

$service = new Service();
$controller = new Controller($service);
//you don't do such a thing, do you?

....(通常)控制器也不使用setter函数。

尽管如此,我仍然在互联网上看到这种方法,包括ASP.NET's doc

将依赖项注入控制器而不是使用new关键字在构造函数中实例化类真的有好处吗? (如果是这样,这种方法如何改善您的代码?)

1 个答案:

答案 0 :(得分:1)

好吧

因此,在使用DI时,通常是将接口注入到控制器中吗?

如果您要换出执行该怎么办? 例如,您有一个ISearchApi,当前您已在自己的DI代码中将其设置为ISearchApi的实现为GoogleApi,现在您想将其交换为BingApi。您无需触摸任何现有代码,因为所有代码都在接口后面被抽象了。这是Dependency Inversion Principle的一部分。

如果BingApi的实现还期望构造函数中有另一个类怎么办?并且该类还期望在其构造函数中有更多这样的类:

new BingApi(new BingControls(new Api(new HttpClient, "ApiKey")));

这将很难维持,如果在您的DI容器中正确设置了它,那么您就不必为此担心。

另一个原因是进行单元测试。我将不讨论控制器在逻辑方面应该做什么。但是,对期望有具体实现的控制器进行单元测试会更加困难,特别是如果该实现调用任何服务/数据库。由于控制器只是new对其进行模拟,因此无法模拟。

我能看到的依赖注入的唯一缺点是,在应用程序启动时还有更多的代码要写。但是考虑到所提供的好处,这是非常小的。