可以在控制器中使用 IKernel 吗?

Is it ok to use IKernel in Controllers?

我有一个包含许多不同 Action 的 MVC 控制器。我使用 Ninject 进行依赖注入。

每个操作都需要一些特定的依赖项。

如何更好地注入这些依赖项?

  1. 将它们全部注入到Controller中,并使用我需要的。

  2. 只在Controller中注入IKernel,获取当前执行的action中的依赖

我认为方法 #2 更好,因为我可以避免创建一些不会被使用的依赖项。

示例 1:

public class MyController : Controller
{
    private readonly IService1 _service1;
    private readonly IService2 _service2;
    private readonly IService3 _service3;
    public MyController(IService1 service1, IService2 service2, IService3 service3)
    {
        _service1 = service1;
        _service2 = service2;
        _service3 = service3;
    }

    public ActionResult Action1()
    {
        _service1.Get();
        return View();
    }

    public ActionResult Action2()
    {
        _service2.Get();
        return View();
    }

    public ActionResult Action3()
    {
        _service3.Get();
        return View();
    }
}

示例 2:

public class MyController : Controller
{
    private readonly IKernel _kernel;
    public MyController(IKernel kernel)
    {
        _kernel = kernel;
    }

    public ActionResult Action1()
    {
        IService1 _service1 = _kernel.Get<IService1>();
        _service1.Get();

        return View();
    }

    public ActionResult Action2()
    {
        IService2 _service2 = _kernel.Get<IService2>();
        _service2.Get();

        return View();
    }

    public ActionResult Action3()
    {
        IService3 _service3 = _kernel.Get<IService3>();
        _service3.Get();

        return View();
    }
}

您所描述的是使用 NinjectIKernel 作为服务定位器,Mark Seemann 定义的是一种反模式 (source)

Service Locator is a well-known pattern, and since it was described by Martin Fowler, it must be good, right?

No, it's actually an anti-pattern and should be avoided.

他用细节和例子解释了为什么 Service Locator 是反模式,例如

  • API usage issues
  • Maintenance issues

您还可以查看 this 问题了解更多信息

如您所知,示例 #2 是 服务定位器模式。我们中的许多人在过去的好日子里都在 ASP.Net Web 表单中使用过它 - 那时我们还不知道更好。

但是,ASP.Net MVC 存在更好的替代方案,例如构造函数注入 - DI 的默认目标 - 示例 #1。

服务定位器几乎没有问题。其中之一就是不遵循不叫我们,我们就叫你的原则。相反,我们直接索要我们需要的东西,而不是交给我们。

使用服务定位器,我们必须检查代码,搜索用于检索所需服务的反复无常的调用。构造函数注入允许我们查看 通过 IntelliSense 查看构造函数或在远处查看所有依赖项。

来源:Dependency Injection in .NET by Mark Seemann and Adaptive Code via C# by Gary McLean Hall