通常,动作方法将以这样的结尾结束:
state1
但是如果我的模型要注入服务,它就不会有默认的ctor。所以它必须看起来像这样:
state2
但如果服务有依赖关系,那就更像是:
return View(new Model());
...开始变得荒谬。这不是IoC容器的用途吗?所以我很想写一些更像这样的东西:
return View(new Model(new Service());
但为了获得return View(new Model(new Service(new Repository())));
,必须将其注入我的控制器,我听到injecting the container itself is an anti-pattern。
那么正确的方法是什么?当我从action方法返回视图时,如何将依赖项传递给模型?
答案 0 :(得分:1)
但是如果我的模型要注入服务
首先防止让您的视图模型具有依赖关系。视图模型应该是哑数据容器,并且应该在控制器操作返回时完全构造它们。这简化了视图和模型,并完全防止了这种情况。
如果您确实希望将依赖项传递给视图模型,则应该没有理由传递依赖项的依赖项。您只需要传入依赖项,并且由于您的控制器是一个应用程序组件,因此它会将该依赖项注入其构造函数中。所以它通常如下所示:
public class HomeController : Controller
{
private readonly IService service;
public HomeController(IService service)
{
this.service = service;
}
public ViewResult Index()
{
return View(new Model(this.service));
}
}
由于DI容器将构建HomeController
及其依赖关系(这意味着Service
将使用Repository
建立),您可以传递service
1}}依赖,而不必知道它的依赖性。
我听说注入容器本身就是一种反模式。
这是对的。使用Composition Root之外的Container
是一个坏主意。
答案 1 :(得分:1)
你是对的。正确地执行依赖注入会使代码更清晰,但会添加执行注入和初始化的混乱代码。这就是DI框架到位的地方。它们的主要目标是处理与您类似的情况 - 删除混乱的构造函数注入代码而无需传递容器。使用像Ninject这样的DI框架,您的代码将如下所示:
IKernel kernel = new StandardKernel();
Bind<View>();
Bind<Model>();
Bind<Service>();
Bind<Repository>();
var view = kernel.Get<View>();
这两篇文章中将显示您手动执行的操作与DI框架将执行的操作之间的对比:
顺便说一下,还有很多其他好的DI框架。你不需要服用Ninject,所有这些基本概念都是一样的。答案 2 :(得分:0)
我使用了在引导程序代码中初始化的静态容器对象,但有时我不得不在容器中传递容器。有些代码闻到了,但想象一下有很多依赖的程序。但是如果你将DI与MVC一起使用,你就会自动注入容器,这就是我看到的模式(查看Autofac MVC)。