【问题标题】:Using IoC to resolve model objects in Action Methods使用 IoC 解析动作方法中的模型对象
【发布时间】:2011-12-30 15:41:24
【问题描述】:

我在 Asp.Net MVC 3 中使用 IoC 容器进行依赖注入,在我开始在控制器中编写 Action 方法之前,一切似乎都很完美。在操作方法中创建实体/模型对象的最佳方法是什么?有时模型是从某个存储库或服务中检索到的,这些存储库或服务通过构造函数注入到控制器中,但系统中的许多其他模型对象并非如此。

【问题讨论】:

  • 你能告诉我们更多细节吗?如果某些模型对象不是来自存储库或服务,那么它们来自哪里?如果你正在创建新的模型对象,你可以注入一个模型工厂/构建器作为依赖..
  • 实际上有一个控制器,它有几个步骤,如果不是所有的动作,大多数(如果不是所有的话)都会生成具有不同模型的不同视图并设置为视图模型。 HtmlHelper 需要一个空对象集作为模型来使用它的扩展方法来显示一个表单来接受数据,并且这个视图的视图模型具有某些特定实体类型的属性,比如SiteSettings 类。我不确定如何从 Action 方法中解决 ViewModel 及其依赖关系。
  • 我认为您提出的原始问题与您可能打算提出的问题不同。这个问题是关于如何使用 IOC 容器来解析动作中的对象。您真正的问题听起来可能是“如何在 ASP.NET MVC 中创建向导?”,我认为正确的答案是在操作方法中使用 IOC 容器。如果您提出新问题,您可能会得到更好的解决方案。
  • @PaulStovell 实际上,我在 IoC 方面遇到了一些问题。我想要的是,有一个简单的 Action 方法,它只创建一个具有设置类作为属性的视图模型。我想,我会将这些视图模型和其他实体(如Settings)与其他实体一起注册到 IoC,它会为我创建它,这就是我所做的。从下面的答案之一,我认为我做错了。那么,这些仅由控制器的一种或两种方法使用的视图模型和简单的支持类可以直接使用new创建吗?而且我不是在寻求帮助来创建向导!

标签: c# asp.net-mvc dependency-injection inversion-of-control


【解决方案1】:

IOC 容器最适合用于创建组件;但它不应该用于创建模型对象。例如,这是

public ActionResult SignUp(string username, string password)
{
    var user = new User();    // Your model object
    user.Username = username; //...

    _repository.Save(user);

    return Redirect(...); 
}

模型对象本身不应该有任何依赖,因此它不应该需要从 IOC 容器中解析。这同样适用于视图模型:

public ActionResult Show(int userId)
{
    var user = _repository.Load<User>(userId);

    var model = new ShowUserModel(user);
    return View(model);
}

创建后,模型/视图模型应该是有效的只读模型,因此它需要的任何信息都应该通过控制器传递——它不应该采用注入的依赖项。

如果你真的真的需要在动作中动态创建组件,你可以这样做:

class HomeController : Controller
{
     readonly Func<IFooService> _fooServiceFactory;

     public HomeController(Func<IFooService> fooServiceFactory)
     {
         _fooServiceFactory = fooServiceFactory;
     }

     public ActionResult SomeAction() 
     {
         var service = _fooServiceFactory(); // Resolves IFooService dynamically
         service.DoStuff();
     }
}

任何体面的 IOC 容器都应该能够处理Func&lt;T&gt; 注入。

【讨论】:

  • 为什么不直接使用普通的构造函数注入。并不是说我反对 Func 。 . .
  • 我同意,理想情况下你会。但是问题的标题是“使用 IoC 来解析模型对象在动作方法中”(尽管我怀疑有更好的方法来实现真正的目标)。
  • 现实世界的情况可能是您有六个动作,其中只有一个需要IFooService,而创建IFooService 的成本很高。在这种情况下,我们可以将IFooService 的解析推迟到操作,这样不需要它的操作就不会解析它。也就是说,这可能意味着IFooService 开始存在设计问题:)
  • 或者IWhateverController中的设计问题——你可能想围绕昂贵的服务构建控制器。
【解决方案2】:

您不使用 DI 容器来解析操作参数。这就是 model binder 在 ASP.NET MVC 中的用途。顺便说一句,您的操作应该将任何域模型作为参数 => 他们应该只采用视图模型。视图模型是专门为满足给定视图的要求而定义的类。

因此,对于某些特定情况,您可以编写自定义模型绑定器,该绑定器将负责您的操作参数的实例化和绑定。就模型绑定器本身的实例化而言,在 ASP.NET MVC 3 中,您可以使用 dependency resolver,它可用于使用您选择的 DI 框架将依赖项注入此模型绑定器。

【讨论】:

  • 模型或视图模型,我不是在谈论发布的数据或参数,所以,我们将如何生成我们需要传递给视图的那些数据,就像从基本的 CRUD 控制器的 @ 987654323@操作方法。那么,视图模型可以直接创建吗?
  • @Threecoins,我不确定我明白你在问什么。您传递给视图的数据是在视图模型的形式下。视图模型是您定义并包含此视图所需信息的类。然后,您的控制器操作将查询存储库以获取域模型,然后将此域模型映射到视图模型并将视图模型传递给视图。也许您可以显示一些代码来更好地解释您的问题?
  • @DarinDimitrov 如果你应该使用 Autofac 来实现这样的模型绑定器,那就太棒了。
猜你喜欢
  • 1970-01-01
  • 2015-07-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-07
  • 2021-01-06
  • 2022-01-24
相关资源
最近更新 更多